Splat

> Ah, I see, at least for #1. I'm assuming that to get the function that
takes a tuple, you'd have to explicitly use the parameters: overload:

Probably; otherwise this doesn't actually save the type checker much.

There's a bit of a complication when talking about type signatures.
Currently, the fact that a function operates on a tuple is embedded in our
type syntax, and the parentheses around the argument list are optional and
represent a tuple—`(Int, String) -> String` is equivalent to
`TupleOfIntAndString -> String`. This might now need a change, or at least
a clarification. For the purposes of this post, I'll say that `(Int,
String) -> String` is the type of a function taking an Int and String,
while `((Int, String)) -> String` is the type of a function taking a tuple.

For the `concatenate(_:to:)` example, the original function has a
signature of `(Int, String) -> String` (once argument labels are fully part
of the name, which seems to be the trend). For each of the syntaxes I
proposed, the type of this expression is `((Int, String)) -> String`:

        concatenate(parameters:)
        concatenate(_:to:).apply(to:)
        concatenate(_:to: *)

> let f = concatenate(_:to:).apply(to:) // I assume this has type (Int,
String) -> String
> var g = f.apply(to:) // Is this legal? What's the type?

That's an interesting question. Swift does not have 1-tuples, so unary
functions might not have an `apply(to:)` method.

> // This type signature is wrong, g takes an arbitrary argument
list...but how do I write that?
> func compose<Params, Intermediate, Result>(f: Intermediate -> Result ,
g: Params -> Intermediate) -> Result {
> return { args in f.apply(to: g.apply(to: args)) }
> }

Without something along the lines of the `@splatting` annotation in a
parameter list, it would not be possible to write a `compose(_:_:)`
function which could operate on non-unary functions directly. Instead of
writing `compose(f, g)`, you'd have to write `compose(f.apply, g.apply)`.

If you think that's kind of ugly, I don't disagree.

> // Here's a function that takes an Array of functions and applies them
one after another...
> // I don't really know where to start with this...the types of all of
its arguments seem inexpressible
> func composeMany</* ...arbitrary many intermediate params...
*/>(functions: [/* What type for arbitrary function? */]) {
> reduce(compose, functions, identity)
> }

Even with the current implicit splatting, this is impossible to express
unless all functions have the same argument and return type. The generics
system is simply not equipped to handle arbitrarily many generic types.

> But then if it looks like a method, people are going to wonder why they
can't pass it to a function or store it in a data-structure.

I'm not sure why you think it can't be stored. I think it can.

Not the result of the splatting operation, but the splatting operation
itself:

let legal = [f, g)
let illegal = [f.apply, g.apply] // But it certainly looks like an
expression that would normally be legal!

> I saw that, briefly. I hope that something like that makes it in, but
it has similar issues with "What's the type signature of this operator, and
if the only way it can exist is as compiler-supported syntax, how do we
make it clear to users that this is a compiler language feature and not a
first-class function call?" IIRC the syntax suggested there made use of
the #thisIsACompilerDirective naming convention. I wonder if that might be
appropriate here:
>
> f(#splat(tuple))
> concatenate(_: #splat)
>
> The latter form also suggests a way this could be used for partial
application:
>
> concatenate(2, #splat) returns a closure where the first argument is
always 2, but any remaining arguments are pulled from the provided tuple.

I don't really think # is a good fit here. I think it's best used in
places where it's performing a relatively straightforward textual
substitution; in the `concatenate(_: #splat)` case, that's not really
what's being done here.

(To tell the truth, in my head I imagine that when we finally get a macro
system in Swift N, all macros are marked by a leading #. So I tend to get a
little squeamish about # uses which draw heavily from context instead of
relying on what you "pass" to them.)

The "..." syntax that's been batted around here looks fine to me as well.

···

On Wed, Feb 10, 2016 at 8:37 PM, Brent Royal-Gordon <brent@architechies.com> wrote: