[swift-evolution] SE-0066 Reaction

Mishal Awadah a.mamish at gmail.com
Tue Apr 26 17:37:08 CDT 2016


On Tue, Apr 26, 2016 at 11:23 AM, Chris Lattner <clattner at apple.com> wrote:

> On Apr 26, 2016, at 10:52 AM, Mishal Awadah via swift-evolution <
> swift-evolution at swift.org> wrote:
> > Concern 1:
> > I feel like we're forgetting about the functional programming syntax of
> declaring function types like this:
> >
> > A -> B -> C
> >
> > for a function foo(a: A, b: B) -> C
>
> This analogy doesn’t exist in Swift, languages like Haskell have
> auto-currying behavior like this, but Swift does not.
>

Indeed, my point is that this proposal drives the distance further from
this analogy, which is a nice one, because function application is still
relevant in Swift, and may be more so in the future. That is to say, this
is closing a functional programming door. I am contrasting this proposal to
Haskell's type system, not the existing Swift one, to increase the
awareness of the direction this is going.

In summary: I am concerned that by doing this we will never do the
Haskell-style type annotations, which feel more at home in Swift.

Obviously, if the Haskell-style annotations are a given "we are never going
to adopt this in Swift", then I cannot argue with the increased clarity
that 0066 provides, despite the unpleasant parenthesis proliferation it
will cause.


>
> >
> > This eliminates the ambiguity of what the parameter types are, and is
> more legible (less paren hell) than adding parens like this:
> >
> > (A,B) -> C
> >
> > which for a function
> >
> > foo(a: (A, B)) -> C
> >
> > would look like this after the implementation of SE-0066:
> >
> > ((A,B)) -> C
> >
> > instead of
> >
> > (A,B) -> C
>
> I’m not sure what the actual concern you’re pointing out here.  However,
> you are forgetting the argument labels.  Your foo example will have type:
>
> (a: (A,B)) -> C
>
> More to the point thought, this example is *exactly* why SE-0066 is the
> right thing to do.  You cannot currently write the type of “foo” as "(A,B)
> -> C”.  (with or without labels), because of the grammar ambiguities that
> SE-0066 fixes.
>
> That said, it is likely that I’m totally missing your point here, can you
> please restate your concern?
>
>
I'm confused, I created this function and got the type without argument
label annotation.

func happy(a: (Int, Int)) -> String {

    return "Happy"

}


print(happy.dynamicType)

// prints: (Int, Int) -> String


The concern is that rather than move towards a more Haskell-like syntax
(which removes ambiguity of tuple params over multiple params as well) this
is adding more parens and making it look less pleasant to read. Contrast
the types of these functions in the Haskell-Style, and the proposed 0066
style:

Haskell Style: (Int, Int) -> String
0066 Style: ((Int, Int)) -> String

The Haskell Style would remove the ambiguity against a function like this:

func unhappy(a: Int, b: Int) -> String {

    return "Unhappy"

}


print(unhappy.dynamicType)

//prints:(Int, Int) -> String

Haskell Style: Int -> Int -> String
0066 Style: (Int, Int) -> String

Now compare these two functions in their respective styles, which one is
clearer to parse at glance?

// haskell style

// happy: (Int, Int) -> String

// unhappy: Int -> Int -> String


// 0066 style

// happy: ((Int, Int)) -> String

// unhappy: (Int, Int) -> String

Perhaps I am jaded from spending time in a functional programming world
(although really not that much), but it is definitely going to take me a
while to see that unhappy is accepting 2 separate params, rather than a
single tuple params. I think this is more because of how we represent tuple
types (like array types) as (Int, Int) or [Int] everywhere else.

In the wild, a tuple type looks like this:

foo: (Int, Int)

but for functions we'll use

fooFunc: ((Int, Int)) -> ()



> > Concern 2:
> >
> > There's also the potential to transform a function like this
> >
> > A -> B -> C
> >
> > into this
> >
> > B -> C
> >
> > after partial application, something which might not be totally
> irrelevant to Swift in its future.
>
> This isn’t affected by SE-0066 - what is your concern?  With SE-0066, the
> transformation is:
>
> (A) -> (B) -> C
> into:
> (B) -> C
>
> Please keep in mind that SE-0066 doesn’t change the type system, it just
> adds parens in a very narrow case.
>

I was thinking about partial function application in the context of
ordinary functions (i.e. not those that explicitly return functions as
well), should that ever be an interesting direction for Swift to head into.

Otherwise, if we look at functions that explicitly return functions, you
could still get a nice function type in the Haskell way if you paren the
return type:

A -> (B -> C)

which reads more simply to me.

(A) -> (B) -> C isn't as clear to parse in this way, but with practice it
doesn't seem like it would be hard to get used to. Perhaps some confusing
instances would be:

(A) -> (B) -> (C) where (C) is a single tuple of type C.


- Mish


>
> >
> >
> > Here are a few contrived examples of function types showing the paren
> version (order 66), the parens on the return type too, and the generic
> functional programming version (right). I want to preface this with,
> "Remember that Swift is an enjoyable experience because reading Swift is
> pleasant.”
>
> 0066 does not affect the return type of a function.
>
> -Chris
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160426/163bf032/attachment.html>


More information about the swift-evolution mailing list