[swift-evolution] SE-0066 Reaction
Chris Lattner
clattner at apple.com
Wed Apr 27 00:19:42 CDT 2016
On Apr 26, 2016, at 3:37 PM, Mishal Awadah <a.mamish at gmail.com> wrote:
> 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.
Hi Mish,
I’m also fond of Haskell and the MLs, and I appreciate many of the choices that they made in the context of their languages. However, there are a large number of deep differences between the type system in Swift and the type system in Haskell that motivate the current behavior we have in Swift.
SE-0066 is a very narrow proposal - it only affects syntax, not semantics. The type system semantics that you seem interested in are unlikely to happen regardless of the syntax changes SE-0066 imply, and SE-0066 doesn’t have anything to do with that.
-Chris
>
> 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/4f047ae0/attachment.html>
More information about the swift-evolution
mailing list