[Proposal] Automating Partial Application via Wildcards


(Erica Sadun) #1

First draft. Let's go Scala!

-- E

Automating Partial Application via Wildcards

Proposal: TBD
Author(s): Erica Sadun <http://github.com/erica>, Davide De Franceschi <http://github.com/DeFrenZ>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/6327981d42eb9be6b4d2#introduction>Introduction

SE-0002 <https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md> has been accepted for Swift 3.0. That proposal removes currying func declaration syntax from Swift. It reasons that currying introduces unnecessary language and implementation complexity and is easily replaced with chained function return types.

Because of SE-0002, this curried example:

public func projectFunctionToCoordinateSystem(function f: FunctionType)(p0: CGPoint, p1: CGPoint)(x: CGFloat) -> CGPoint
becomes

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
in Swift 3.

It's mechanically simple to re-introduce partial application but the current solution adds unnecessary nesting and complicated closure declarations, as you see in the following Swift 3 version of this projection function.

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint {
  return { p0, p1 in
    return { x in
      let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
      let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
      var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
      return CGPoint(x: outPoint.x, y: outPoint.y)
    }
  }
}
SE-0002 mentions the possibility of introducing Scala-style free-form partial implementation as a future step. This proposal requests that a Scala-style wildcard feature be adopted into Swift by introducing a form of automatic partial application.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#detail-design>Detail Design

The proposed design replaces a Swift 3 curried signature like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
with a non-curried, fully qualified call like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint
When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)

let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
// partial2(p1: p1Value, x: xValue)
// or
// let partial3 = partial2(p1: p1Value, x: _); partial3(x: 0.25)
This returns a curried form. Labels are retained and used, and the compiler should throw an error for any ambiguity that arises as a side effect.

The function implementation is fully configured as if all parameters are specified, losing all its nested params in/params in/params in... overhead:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint {
  let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
  let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
  var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
  return CGPoint(x: outPoint.x, y: outPoint.y)
}
The result is simple, readable, and written independently of how the currying is to be applied. as under this design, any parameter can be curried.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#alternatives-considered>Alternatives Considered

Although our natural inclination is to use standard currying and partial application, we also considered defaulting arguments. In this scenario, wildcards return a version of the function with defaulted arguments for all non-wildcard values. In such a design,

let defaultedVersion = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
could be called with a p0 parameter even though that same parameter was already specified in the assignment as in the following example. So this:

defaultedVersion(p0: myNewOrigin, p1: myPoint, x: 0.5)
expands to:

defaultedVersionOfProjectFunctionToCoordinateSystem(function: mySinFunction, p0: myNewOrigin, p1: myPoint, x: 0.5)
where the new version of p0 overrides the defaulted version created in the initial wildcard assignment.

The implementation details for this alternative approach would differ but it might be easier to implement. As you'd expect, any function called with fully qualified arguments would be executed rather than returning a defaulted version (or a partially applied version for the non-alternative implementation).


(Michael Ilseman) #2

First draft. Let's go Scala!

-- E

Automating Partial Application via Wildcards

Proposal: TBD
Author(s): Erica Sadun <http://github.com/erica>, Davide De Franceschi <http://github.com/DeFrenZ>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/6327981d42eb9be6b4d2#introduction>Introduction

SE-0002 <https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md> has been accepted for Swift 3.0. That proposal removes currying func declaration syntax from Swift. It reasons that currying introduces unnecessary language and implementation complexity and is easily replaced with chained function return types.

Because of SE-0002, this curried example:

public func projectFunctionToCoordinateSystem(function f: FunctionType)(p0: CGPoint, p1: CGPoint)(x: CGFloat) -> CGPoint
becomes

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
in Swift 3.

It's mechanically simple to re-introduce partial application but the current solution adds unnecessary nesting and complicated closure declarations, as you see in the following Swift 3 version of this projection function.

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint {
  return { p0, p1 in
    return { x in
      let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
      let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
      var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
      return CGPoint(x: outPoint.x, y: outPoint.y)
    }
  }
}
SE-0002 mentions the possibility of introducing Scala-style free-form partial implementation as a future step. This proposal requests that a Scala-style wildcard feature be adopted into Swift by introducing a form of automatic partial application.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#detail-design>Detail Design

The proposed design replaces a Swift 3 curried signature like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
with a non-curried, fully qualified call like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint
When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)

let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
// partial2(p1: p1Value, x: xValue)
// or
// let partial3 = partial2(p1: p1Value, x: _); partial3(x: 0.25)
This returns a curried form. Labels are retained and used, and the compiler should throw an error for any ambiguity that arises as a side effect.

To someone more familiar with the implementation of type checking than myself: how much would this complicate overload resolution, as there are no constraints or contextual typing information present in “_”? Would this, in practice, be any worse than something like:

func foo(a : Int, b b: Int?) -> Int {
    if let b = b {
        return a + b
    }
    return a
}
func foo(a : Int, b b: Float?) -> Float {
    if let b = b {
        return Float(a) + b
    }
    return Float(a)
}

let a = foo(1, b: 2) // Int: 3
let b = foo(1, b: 2.0) // Float: 3
let c = foo(1, b: nil) // Error: ambiguous use of 'foo(_:b:)'

···

On Feb 2, 2016, at 9:33 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

The function implementation is fully configured as if all parameters are specified, losing all its nested params in/params in/params in... overhead:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint {
  let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
  let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
  var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
  return CGPoint(x: outPoint.x, y: outPoint.y)
}
The result is simple, readable, and written independently of how the currying is to be applied. as under this design, any parameter can be curried.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#alternatives-considered>Alternatives Considered

Although our natural inclination is to use standard currying and partial application, we also considered defaulting arguments. In this scenario, wildcards return a version of the function with defaulted arguments for all non-wildcard values. In such a design,

let defaultedVersion = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
could be called with a p0 parameter even though that same parameter was already specified in the assignment as in the following example. So this:

defaultedVersion(p0: myNewOrigin, p1: myPoint, x: 0.5)
expands to:

defaultedVersionOfProjectFunctionToCoordinateSystem(function: mySinFunction, p0: myNewOrigin, p1: myPoint, x: 0.5)
where the new version of p0 overrides the defaulted version created in the initial wildcard assignment.

The implementation details for this alternative approach would differ but it might be easier to implement. As you'd expect, any function called with fully qualified arguments would be executed rather than returning a defaulted version (or a partially applied version for the non-alternative implementation).
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Austin Zheng) #3

I like this ad-hoc currying proposal.

Questions:
- How does this handle inout params? Are they just not allowed, to keep things simple? Or are they allowed as long as they aren't the parameter being curried?
- Would you be able to curry arbitrary params in the function decl, or only the n rightmost params?

Best,
Austin

···

On Feb 2, 2016, at 10:10 AM, Michael Ilseman via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 2, 2016, at 9:33 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

First draft. Let's go Scala!

-- E

Automating Partial Application via Wildcards

Proposal: TBD
Author(s): Erica Sadun <http://github.com/erica>, Davide De Franceschi <http://github.com/DeFrenZ>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/6327981d42eb9be6b4d2#introduction>Introduction

SE-0002 <https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md> has been accepted for Swift 3.0. That proposal removes currying func declaration syntax from Swift. It reasons that currying introduces unnecessary language and implementation complexity and is easily replaced with chained function return types.

Because of SE-0002, this curried example:

public func projectFunctionToCoordinateSystem(function f: FunctionType)(p0: CGPoint, p1: CGPoint)(x: CGFloat) -> CGPoint
becomes

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
in Swift 3.

It's mechanically simple to re-introduce partial application but the current solution adds unnecessary nesting and complicated closure declarations, as you see in the following Swift 3 version of this projection function.

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint {
  return { p0, p1 in
    return { x in
      let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
      let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
      var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
      return CGPoint(x: outPoint.x, y: outPoint.y)
    }
  }
}
SE-0002 mentions the possibility of introducing Scala-style free-form partial implementation as a future step. This proposal requests that a Scala-style wildcard feature be adopted into Swift by introducing a form of automatic partial application.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#detail-design>Detail Design

The proposed design replaces a Swift 3 curried signature like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
with a non-curried, fully qualified call like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint
When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)

let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
// partial2(p1: p1Value, x: xValue)
// or
// let partial3 = partial2(p1: p1Value, x: _); partial3(x: 0.25)
This returns a curried form. Labels are retained and used, and the compiler should throw an error for any ambiguity that arises as a side effect.

To someone more familiar with the implementation of type checking than myself: how much would this complicate overload resolution, as there are no constraints or contextual typing information present in “_”? Would this, in practice, be any worse than something like:

func foo(a : Int, b b: Int?) -> Int {
    if let b = b {
        return a + b
    }
    return a
}
func foo(a : Int, b b: Float?) -> Float {
    if let b = b {
        return Float(a) + b
    }
    return Float(a)
}

let a = foo(1, b: 2) // Int: 3
let b = foo(1, b: 2.0) // Float: 3
let c = foo(1, b: nil) // Error: ambiguous use of 'foo(_:b:)'

The function implementation is fully configured as if all parameters are specified, losing all its nested params in/params in/params in... overhead:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint {
  let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
  let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
  var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
  return CGPoint(x: outPoint.x, y: outPoint.y)
}
The result is simple, readable, and written independently of how the currying is to be applied. as under this design, any parameter can be curried.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#alternatives-considered>Alternatives Considered

Although our natural inclination is to use standard currying and partial application, we also considered defaulting arguments. In this scenario, wildcards return a version of the function with defaulted arguments for all non-wildcard values. In such a design,

let defaultedVersion = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
could be called with a p0 parameter even though that same parameter was already specified in the assignment as in the following example. So this:

defaultedVersion(p0: myNewOrigin, p1: myPoint, x: 0.5)
expands to:

defaultedVersionOfProjectFunctionToCoordinateSystem(function: mySinFunction, p0: myNewOrigin, p1: myPoint, x: 0.5)
where the new version of p0 overrides the defaulted version created in the initial wildcard assignment.

The implementation details for this alternative approach would differ but it might be easier to implement. As you'd expect, any function called with fully qualified arguments would be executed rather than returning a defaulted version (or a partially applied version for the non-alternative implementation).
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #4

One superficial comment on this: the use of _ here is a bad idea. _ already means something in expressions - “discard”, and a closely related thing in declarations - “ignore”.

Adding a third very different thing (placeholder to be filled in later) seems like a really confusing thing to do.

-Chris

···

On Feb 2, 2016, at 9:33 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)


(Douglas Gregor) #5

In the SE-0021 acceptance rationale at

  http://article.gmane.org/gmane.comp.lang.swift.evolution/3961/match=accepted+0021

Joe Groff sayeth:

A number of contributors proposed an alternative syntax, using a placeholder in the argument value position:

let x = Foo.bar(_, bas: _)

with the idea that this could potentially generalize to partial application syntax. We don't think this is a good direction for Swift for a couple of reasons. Swift already has fairly compact syntax for forming closures over partially applied functions, { Foo.bar($0, bas: $1) }. It may not be everyone's aesthetic cup of tea, but this notation has several important advantages. The braces unambiguously delineate the boundaries of the closure, which is a subtle problem with Scala-like approaches. The braces also provide a visual cue that capture is occurring. The $n placeholders are also more general since they allow for reordering of arguments. '_' in particular is also a poor choice of placeholder, since in other contexts where it's used, it's meant as a "black hole" for value binding in patterns rather than as a placeholder for a meaningful bound value.

  - Doug

···

On Feb 2, 2016, at 9:33 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

First draft. Let's go Scala!

-- E

Automating Partial Application via Wildcards

Proposal: TBD
Author(s): Erica Sadun <http://github.com/erica>, Davide De Franceschi <http://github.com/DeFrenZ>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/6327981d42eb9be6b4d2#introduction>Introduction

SE-0002 <https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md> has been accepted for Swift 3.0. That proposal removes currying func declaration syntax from Swift. It reasons that currying introduces unnecessary language and implementation complexity and is easily replaced with chained function return types.

Because of SE-0002, this curried example:

public func projectFunctionToCoordinateSystem(function f: FunctionType)(p0: CGPoint, p1: CGPoint)(x: CGFloat) -> CGPoint
becomes

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
in Swift 3.

It's mechanically simple to re-introduce partial application but the current solution adds unnecessary nesting and complicated closure declarations, as you see in the following Swift 3 version of this projection function.

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint {
  return { p0, p1 in
    return { x in
      let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
      let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
      var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
      return CGPoint(x: outPoint.x, y: outPoint.y)
    }
  }
}
SE-0002 mentions the possibility of introducing Scala-style free-form partial implementation as a future step. This proposal requests that a Scala-style wildcard feature be adopted into Swift by introducing a form of automatic partial application.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#detail-design>Detail Design

The proposed design replaces a Swift 3 curried signature like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
with a non-curried, fully qualified call like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint
When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)

let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
// partial2(p1: p1Value, x: xValue)
// or
// let partial3 = partial2(p1: p1Value, x: _); partial3(x: 0.25)


(Erica Sadun) #6

#?

-- E, since it was freed up in the label liberation movement

···

On Feb 2, 2016, at 11:15 AM, Chris Lattner <clattner@apple.com> wrote:

On Feb 2, 2016, at 9:33 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)

One superficial comment on this: the use of _ here is a bad idea. _ already means something in expressions - “discard”, and a closely related thing in declarations - “ignore”.

Adding a third very different thing (placeholder to be filled in later) seems like a really confusing thing to do.

-Chris


(Erica Sadun) #7

I would not want to have to deal with inout, as "bad things could happen"™ And I'm imagining arbitrary params, not just rightmost,
although I would defer to implementation realities (such as not using _) as needed.

-- E

···

On Feb 2, 2016, at 11:14 AM, Austin Zheng <austinzheng@gmail.com> wrote:

I like this ad-hoc currying proposal.

Questions:
- How does this handle inout params? Are they just not allowed, to keep things simple? Or are they allowed as long as they aren't the parameter being curried?
- Would you be able to curry arbitrary params in the function decl, or only the n rightmost params?

Best,
Austin

On Feb 2, 2016, at 10:10 AM, Michael Ilseman via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 2, 2016, at 9:33 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

First draft. Let's go Scala!

-- E

Automating Partial Application via Wildcards

Proposal: TBD
Author(s): Erica Sadun <http://github.com/erica>, Davide De Franceschi <http://github.com/DeFrenZ>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/6327981d42eb9be6b4d2#introduction>Introduction

SE-0002 <https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md> has been accepted for Swift 3.0. That proposal removes currying func declaration syntax from Swift. It reasons that currying introduces unnecessary language and implementation complexity and is easily replaced with chained function return types.

Because of SE-0002, this curried example:

public func projectFunctionToCoordinateSystem(function f: FunctionType)(p0: CGPoint, p1: CGPoint)(x: CGFloat) -> CGPoint
becomes

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
in Swift 3.

It's mechanically simple to re-introduce partial application but the current solution adds unnecessary nesting and complicated closure declarations, as you see in the following Swift 3 version of this projection function.

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint {
  return { p0, p1 in
    return { x in
      let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
      let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
      var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
      return CGPoint(x: outPoint.x, y: outPoint.y)
    }
  }
}
SE-0002 mentions the possibility of introducing Scala-style free-form partial implementation as a future step. This proposal requests that a Scala-style wildcard feature be adopted into Swift by introducing a form of automatic partial application.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#detail-design>Detail Design

The proposed design replaces a Swift 3 curried signature like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
with a non-curried, fully qualified call like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint
When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)

let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
// partial2(p1: p1Value, x: xValue)
// or
// let partial3 = partial2(p1: p1Value, x: _); partial3(x: 0.25)
This returns a curried form. Labels are retained and used, and the compiler should throw an error for any ambiguity that arises as a side effect.

To someone more familiar with the implementation of type checking than myself: how much would this complicate overload resolution, as there are no constraints or contextual typing information present in “_”? Would this, in practice, be any worse than something like:

func foo(a : Int, b b: Int?) -> Int {
    if let b = b {
        return a + b
    }
    return a
}
func foo(a : Int, b b: Float?) -> Float {
    if let b = b {
        return Float(a) + b
    }
    return Float(a)
}

let a = foo(1, b: 2) // Int: 3
let b = foo(1, b: 2.0) // Float: 3
let c = foo(1, b: nil) // Error: ambiguous use of 'foo(_:b:)'

The function implementation is fully configured as if all parameters are specified, losing all its nested params in/params in/params in... overhead:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint {
  let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
  let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
  var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
  return CGPoint(x: outPoint.x, y: outPoint.y)
}
The result is simple, readable, and written independently of how the currying is to be applied. as under this design, any parameter can be curried.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#alternatives-considered>Alternatives Considered

Although our natural inclination is to use standard currying and partial application, we also considered defaulting arguments. In this scenario, wildcards return a version of the function with defaulted arguments for all non-wildcard values. In such a design,

let defaultedVersion = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
could be called with a p0 parameter even though that same parameter was already specified in the assignment as in the following example. So this:

defaultedVersion(p0: myNewOrigin, p1: myPoint, x: 0.5)
expands to:

defaultedVersionOfProjectFunctionToCoordinateSystem(function: mySinFunction, p0: myNewOrigin, p1: myPoint, x: 0.5)
where the new version of p0 overrides the defaulted version created in the initial wildcard assignment.

The implementation details for this alternative approach would differ but it might be easier to implement. As you'd expect, any function called with fully qualified arguments would be executed rather than returning a defaulted version (or a partially applied version for the non-alternative implementation).
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #8

# means “macro like” or “compiler synthesized”.

-Chris

···

On Feb 2, 2016, at 10:16 AM, Erica Sadun <erica@ericasadun.com> wrote:

One superficial comment on this: the use of _ here is a bad idea. _ already means something in expressions - “discard”, and a closely related thing in declarations - “ignore”.

Adding a third very different thing (placeholder to be filled in later) seems like a really confusing thing to do.

-Chris

#?


(Austin Zheng) #9

Sounds good! I'm sure a sigil/syntax can be figured out that satisfies everyone.

I think disallowing currying for functions with inout params is a good idea, and in the spirit of avoiding adding huge amounts of complexity for a fringe use case (like with removing the inout closure shadow copying behavior, proposed by Joe).

Austin

···

On Feb 2, 2016, at 10:19 AM, Erica Sadun <erica@ericasadun.com> wrote:

I would not want to have to deal with inout, as "bad things could happen"™ And I'm imagining arbitrary params, not just rightmost,
although I would defer to implementation realities (such as not using _) as needed.

-- E

On Feb 2, 2016, at 11:14 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

I like this ad-hoc currying proposal.

Questions:
- How does this handle inout params? Are they just not allowed, to keep things simple? Or are they allowed as long as they aren't the parameter being curried?
- Would you be able to curry arbitrary params in the function decl, or only the n rightmost params?

Best,
Austin

On Feb 2, 2016, at 10:10 AM, Michael Ilseman via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 2, 2016, at 9:33 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

First draft. Let's go Scala!

-- E

Automating Partial Application via Wildcards

Proposal: TBD
Author(s): Erica Sadun <http://github.com/erica>, Davide De Franceschi <http://github.com/DeFrenZ>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/6327981d42eb9be6b4d2#introduction>Introduction

SE-0002 <https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md> has been accepted for Swift 3.0. That proposal removes currying func declaration syntax from Swift. It reasons that currying introduces unnecessary language and implementation complexity and is easily replaced with chained function return types.

Because of SE-0002, this curried example:

public func projectFunctionToCoordinateSystem(function f: FunctionType)(p0: CGPoint, p1: CGPoint)(x: CGFloat) -> CGPoint
becomes

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
in Swift 3.

It's mechanically simple to re-introduce partial application but the current solution adds unnecessary nesting and complicated closure declarations, as you see in the following Swift 3 version of this projection function.

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint {
  return { p0, p1 in
    return { x in
      let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
      let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
      var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
      return CGPoint(x: outPoint.x, y: outPoint.y)
    }
  }
}
SE-0002 mentions the possibility of introducing Scala-style free-form partial implementation as a future step. This proposal requests that a Scala-style wildcard feature be adopted into Swift by introducing a form of automatic partial application.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#detail-design>Detail Design

The proposed design replaces a Swift 3 curried signature like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
with a non-curried, fully qualified call like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint
When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)

let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
// partial2(p1: p1Value, x: xValue)
// or
// let partial3 = partial2(p1: p1Value, x: _); partial3(x: 0.25)
This returns a curried form. Labels are retained and used, and the compiler should throw an error for any ambiguity that arises as a side effect.

To someone more familiar with the implementation of type checking than myself: how much would this complicate overload resolution, as there are no constraints or contextual typing information present in “_”? Would this, in practice, be any worse than something like:

func foo(a : Int, b b: Int?) -> Int {
    if let b = b {
        return a + b
    }
    return a
}
func foo(a : Int, b b: Float?) -> Float {
    if let b = b {
        return Float(a) + b
    }
    return Float(a)
}

let a = foo(1, b: 2) // Int: 3
let b = foo(1, b: 2.0) // Float: 3
let c = foo(1, b: nil) // Error: ambiguous use of 'foo(_:b:)'

The function implementation is fully configured as if all parameters are specified, losing all its nested params in/params in/params in... overhead:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint {
  let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
  let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
  var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
  outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
  return CGPoint(x: outPoint.x, y: outPoint.y)
}
The result is simple, readable, and written independently of how the currying is to be applied. as under this design, any parameter can be curried.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#alternatives-considered>Alternatives Considered

Although our natural inclination is to use standard currying and partial application, we also considered defaulting arguments. In this scenario, wildcards return a version of the function with defaulted arguments for all non-wildcard values. In such a design,

let defaultedVersion = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
could be called with a p0 parameter even though that same parameter was already specified in the assignment as in the following example. So this:

defaultedVersion(p0: myNewOrigin, p1: myPoint, x: 0.5)
expands to:

defaultedVersionOfProjectFunctionToCoordinateSystem(function: mySinFunction, p0: myNewOrigin, p1: myPoint, x: 0.5)
where the new version of p0 overrides the defaulted version created in the initial wildcard assignment.

The implementation details for this alternative approach would differ but it might be easier to implement. As you'd expect, any function called with fully qualified arguments would be executed rather than returning a defaulted version (or a partially applied version for the non-alternative implementation).
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Austin Zheng) #10

Hmm...the rationale that Joe provided makes a lot of sense.

One question - is the explicit closure syntax amenable to multiple levels of currying? In particular, what are the scoping rules for the placeholders $n - are they limited to the immediate closure within which they appear, or can they be used within further-nested closures?

Best,
Austin

···

On Feb 2, 2016, at 11:01 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 2, 2016, at 9:33 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

First draft. Let's go Scala!

-- E

Automating Partial Application via Wildcards

Proposal: TBD
Author(s): Erica Sadun <http://github.com/erica>, Davide De Franceschi <http://github.com/DeFrenZ>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/6327981d42eb9be6b4d2#introduction>Introduction

SE-0002 <https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md> has been accepted for Swift 3.0. That proposal removes currying func declaration syntax from Swift. It reasons that currying introduces unnecessary language and implementation complexity and is easily replaced with chained function return types.

Because of SE-0002, this curried example:

public func projectFunctionToCoordinateSystem(function f: FunctionType)(p0: CGPoint, p1: CGPoint)(x: CGFloat) -> CGPoint
becomes

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
in Swift 3.

It's mechanically simple to re-introduce partial application but the current solution adds unnecessary nesting and complicated closure declarations, as you see in the following Swift 3 version of this projection function.

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint {
  return { p0, p1 in
    return { x in
      let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
      let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
      var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
      return CGPoint(x: outPoint.x, y: outPoint.y)
    }
  }
}
SE-0002 mentions the possibility of introducing Scala-style free-form partial implementation as a future step. This proposal requests that a Scala-style wildcard feature be adopted into Swift by introducing a form of automatic partial application.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#detail-design>Detail Design

The proposed design replaces a Swift 3 curried signature like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
with a non-curried, fully qualified call like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint
When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)

let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
// partial2(p1: p1Value, x: xValue)
// or
// let partial3 = partial2(p1: p1Value, x: _); partial3(x: 0.25)

In the SE-0021 acceptance rationale at

  http://article.gmane.org/gmane.comp.lang.swift.evolution/3961/match=accepted+0021 <http://article.gmane.org/gmane.comp.lang.swift.evolution/3961/match=accepted+0021>

Joe Groff sayeth:

A number of contributors proposed an alternative syntax, using a placeholder in the argument value position:

let x = Foo.bar(_, bas: _)

with the idea that this could potentially generalize to partial application syntax. We don't think this is a good direction for Swift for a couple of reasons. Swift already has fairly compact syntax for forming closures over partially applied functions, { Foo.bar($0, bas: $1) }. It may not be everyone's aesthetic cup of tea, but this notation has several important advantages. The braces unambiguously delineate the boundaries of the closure, which is a subtle problem with Scala-like approaches. The braces also provide a visual cue that capture is occurring. The $n placeholders are also more general since they allow for reordering of arguments. '_' in particular is also a poor choice of placeholder, since in other contexts where it's used, it's meant as a "black hole" for value binding in patterns rather than as a placeholder for a meaningful bound value.

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Erica Sadun) #11

* would be bad, right? And naked ?-marks?

-- E

···

On Feb 2, 2016, at 11:20 AM, Chris Lattner <clattner@apple.com> wrote:

On Feb 2, 2016, at 10:16 AM, Erica Sadun <erica@ericasadun.com> wrote:

One superficial comment on this: the use of _ here is a bad idea. _ already means something in expressions - “discard”, and a closely related thing in declarations - “ignore”.

Adding a third very different thing (placeholder to be filled in later) seems like a really confusing thing to do.

-Chris

#?

# means “macro like” or “compiler synthesized”.

-Chris


(Joe Groff) #12

Currently, they're always scoped to the immediate closure, so you need to use explicit named parameters if you want to nest closures.

-Joe

···

On Feb 2, 2016, at 11:12 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

Hmm...the rationale that Joe provided makes a lot of sense.

One question - is the explicit closure syntax amenable to multiple levels of currying? In particular, what are the scoping rules for the placeholders $n - are they limited to the immediate closure within which they appear, or can they be used within further-nested closures?


(Douglas Gregor) #13

Hmm...the rationale that Joe provided makes a lot of sense.

If it wasn’t clear, that rationale is from the core team discussion of SE-0021.

I’m very strongly -1 on this.

  - Doug

···

On Feb 2, 2016, at 11:12 AM, Austin Zheng <austinzheng@gmail.com> wrote:

One question - is the explicit closure syntax amenable to multiple levels of currying? In particular, what are the scoping rules for the placeholders $n - are they limited to the immediate closure within which they appear, or can they be used within further-nested closures?

Best,
Austin

On Feb 2, 2016, at 11:01 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Feb 2, 2016, at 9:33 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

First draft. Let's go Scala!

-- E

Automating Partial Application via Wildcards

Proposal: TBD
Author(s): Erica Sadun <http://github.com/erica>, Davide De Franceschi <http://github.com/DeFrenZ>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/6327981d42eb9be6b4d2#introduction>Introduction

SE-0002 <https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md> has been accepted for Swift 3.0. That proposal removes currying func declaration syntax from Swift. It reasons that currying introduces unnecessary language and implementation complexity and is easily replaced with chained function return types.

Because of SE-0002, this curried example:

public func projectFunctionToCoordinateSystem(function f: FunctionType)(p0: CGPoint, p1: CGPoint)(x: CGFloat) -> CGPoint
becomes

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
in Swift 3.

It's mechanically simple to re-introduce partial application but the current solution adds unnecessary nesting and complicated closure declarations, as you see in the following Swift 3 version of this projection function.

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint {
  return { p0, p1 in
    return { x in
      let (dx, dy) = (p1.x - p0.x, p1.y - p0.y)
      let (magnitude, theta) = (hypot(dy, dx), atan2(dy, dx)) // Thanks loooop
      var outPoint = CGPoint(x: x * magnitude, y: f(x) * magnitude)
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeRotation(theta))
      outPoint = CGPointApplyAffineTransform(outPoint, CGAffineTransformMakeTranslation(p0.x, p0.y))
      return CGPoint(x: outPoint.x, y: outPoint.y)
    }
  }
}
SE-0002 mentions the possibility of introducing Scala-style free-form partial implementation as a future step. This proposal requests that a Scala-style wildcard feature be adopted into Swift by introducing a form of automatic partial application.

<https://gist.github.com/erica/6327981d42eb9be6b4d2#detail-design>Detail Design

The proposed design replaces a Swift 3 curried signature like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType) -> (p0: CGPoint, p1: CGPoint) -> (x: CGFloat) -> CGPoint
with a non-curried, fully qualified call like this:

public func projectFunctionToCoordinateSystem(function f: FunctionType, p0: CGPoint, p1: CGPoint, x: CGFloat) -> CGPoint
When called with wildcard tokens, the function is partially applied using the supplied arguments. For example:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
// partial1(x: xValue)

let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)
// partial2(p1: p1Value, x: xValue)
// or
// let partial3 = partial2(p1: p1Value, x: _); partial3(x: 0.25)

In the SE-0021 acceptance rationale at

  http://article.gmane.org/gmane.comp.lang.swift.evolution/3961/match=accepted+0021 <http://article.gmane.org/gmane.comp.lang.swift.evolution/3961/match=accepted+0021>

Joe Groff sayeth:

A number of contributors proposed an alternative syntax, using a placeholder in the argument value position:

let x = Foo.bar(_, bas: _)

with the idea that this could potentially generalize to partial application syntax. We don't think this is a good direction for Swift for a couple of reasons. Swift already has fairly compact syntax for forming closures over partially applied functions, { Foo.bar($0, bas: $1) }. It may not be everyone's aesthetic cup of tea, but this notation has several important advantages. The braces unambiguously delineate the boundaries of the closure, which is a subtle problem with Scala-like approaches. The braces also provide a visual cue that capture is occurring. The $n placeholders are also more general since they allow for reordering of arguments. '_' in particular is also a poor choice of placeholder, since in other contexts where it's used, it's meant as a "black hole" for value binding in patterns rather than as a placeholder for a meaningful bound value.

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


#14

Any operator character would be bad, since the function may accept it, as in `[1,2,3].reduce(1, combine: *)`

Gwendal

···

Le 2 févr. 2016 à 19:24, Erica Sadun via swift-evolution <swift-evolution@swift.org> a écrit :

On Feb 2, 2016, at 11:20 AM, Chris Lattner <clattner@apple.com> wrote:

On Feb 2, 2016, at 10:16 AM, Erica Sadun <erica@ericasadun.com> wrote:

One superficial comment on this: the use of _ here is a bad idea. _ already means something in expressions - “discard”, and a closely related thing in declarations - “ignore”.

Adding a third very different thing (placeholder to be filled in later) seems like a really confusing thing to do.

-Chris

#?

# means “macro like” or “compiler synthesized”.

-Chris

* would be bad, right? And naked ?-marks?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Austin Zheng) #15

That makes sense too. It might be a little less elegant in appearance, but
I think all the expressive power is there.

Thanks for answering my questions; I'm now at +0 with this proposal and
look forward to seeing what other people have to say, for or again.

Austin

···

On Tue, Feb 2, 2016 at 11:26 AM, Joe Groff <jgroff@apple.com> wrote:

On Feb 2, 2016, at 11:12 AM, Austin Zheng via swift-evolution < > swift-evolution@swift.org> wrote:

Hmm...the rationale that Joe provided makes a lot of sense.

One question - is the explicit closure syntax amenable to multiple levels
of currying? In particular, what are the scoping rules for the placeholders
$*n *- are they limited to the immediate closure within which they
appear, or can they be used within further-nested closures?

Currently, they're always scoped to the immediate closure, so you need to
use explicit named parameters if you want to nest closures.

-Joe


#16

What about nothing?

let partial1 = f(arg1: 1, arg2:)
Gwendal

···

Le 2 févr. 2016 à 19:26, Gwendal Roué <gwendal.roue@gmail.com> a écrit :

Any operator character would be bad, since the function may accept it, as in `[1,2,3].reduce(1, combine: *)`

Gwendal

Le 2 févr. 2016 à 19:24, Erica Sadun via swift-evolution <swift-evolution@swift.org> a écrit :

On Feb 2, 2016, at 11:20 AM, Chris Lattner <clattner@apple.com> wrote:

On Feb 2, 2016, at 10:16 AM, Erica Sadun <erica@ericasadun.com> wrote:

One superficial comment on this: the use of _ here is a bad idea. _ already means something in expressions - “discard”, and a closely related thing in declarations - “ignore”.

Adding a third very different thing (placeholder to be filled in later) seems like a really confusing thing to do.

-Chris

#?

# means “macro like” or “compiler synthesized”.

-Chris

* would be bad, right? And naked ?-marks?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Greg Titus) #17

What about $N? :slight_smile:

And then you could also put {} around it so that it is more obvious that partial1 is being assigned something that acts like a closure, and then you end up with:

let partial1 = { projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: $0) }
let partial2 = { projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: $0, x: $1) }

instead of:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)

I’m -1.

With the way that single expression closures work, and the fact that they are so syntactically light, I don’t think that this proposal would add utility, it would just be one more construct to learn.

  - Greg

···

On Feb 2, 2016, at 10:28 AM, Gwendal Roué via swift-evolution <swift-evolution@swift.org> wrote:

What about nothing?

let partial1 = f(arg1: 1, arg2:)
Gwendal

Le 2 févr. 2016 à 19:26, Gwendal Roué <gwendal.roue@gmail.com <mailto:gwendal.roue@gmail.com>> a écrit :

Any operator character would be bad, since the function may accept it, as in `[1,2,3].reduce(1, combine: *)`

Gwendal

Le 2 févr. 2016 à 19:24, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Feb 2, 2016, at 11:20 AM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On Feb 2, 2016, at 10:16 AM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

One superficial comment on this: the use of _ here is a bad idea. _ already means something in expressions - “discard”, and a closely related thing in declarations - “ignore”.

Adding a third very different thing (placeholder to be filled in later) seems like a really confusing thing to do.

-Chris

#?

# means “macro like” or “compiler synthesized”.

-Chris

* would be bad, right? And naked ?-marks?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dave Abrahams) #18

What about nothing?

let partial1 = f(arg1: 1, arg2:)

Other systems have used “_”, and, for reordering parameters, “_0”,
“_1”, ...

let partial1 = f(arg1: 1, arg2: _) // { f(arg1: 1, arg2: $0) }
let partial2 = f(arg1: _1, arg2: _0) // { f(arg1: $1, arg2: $0) }

···

on Tue Feb 02 2016, Gwendal Roué <swift-evolution@swift.org> wrote:

Gwendal

Le 2 févr. 2016 à 19:26, Gwendal Roué <gwendal.roue@gmail.com> a écrit :

Any operator character would be bad, since the function may accept
it, as in `[1,2,3].reduce(1, combine: *)`

Gwendal

Le 2 févr. 2016 à 19:24, Erica Sadun via swift-evolution >>> <swift-evolution@swift.org> a écrit :

On Feb 2, 2016, at 11:20 AM, Chris Lattner >>>> <clattner@apple.com> wrote:

On Feb 2, 2016, at 10:16 AM, Erica Sadun >>>> <erica@ericasadun.com> wrote:

One superficial comment on this: the use of _ here is a bad
idea. _ already means something in expressions - “discard”, and
a closely related thing in declarations - “ignore”.

Adding a third very different thing (placeholder to be filled in
later) seems like a really confusing thing to do.

-Chris

#?

# means “macro like” or “compiler synthesized”.

-Chris

* would be bad, right? And naked ?-marks?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave


(Joe Groff) #19

Yeah, I'm with Greg—I don't think this saves much over an explicit closure with $N arguments. Another problem with '_' is that it's nonobvious what the boundaries of the closure should be. You can say that it's the enclosing function application, but in the AST, a method invocation is two function applications, so by that rule '_.foo(_)' would mean {{ $0.foo }($0)}, and every operator is a separate function call, so '_ + _ + _' would be '{{ $0 + $1 } + $0}', neither of which is likely to be expected. The { $N } syntax is almost as compact, and is both clearer and more general.

-Joe

···

On Feb 2, 2016, at 10:41 AM, Greg Titus via swift-evolution <swift-evolution@swift.org> wrote:

What about $N? :slight_smile:

And then you could also put {} around it so that it is more obvious that partial1 is being assigned something that acts like a closure, and then you end up with:

let partial1 = { projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: $0) }
let partial2 = { projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: $0, x: $1) }

instead of:

let partial1 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: p0, p1: p1, x: _)
let partial2 = projectFunctionToCoordinateSystem(function: mySinFunction, p0: .zero, p1: _, x: _)

I’m -1.

With the way that single expression closures work, and the fact that they are so syntactically light, I don’t think that this proposal would add utility, it would just be one more construct to learn.

  - Greg

On Feb 2, 2016, at 10:28 AM, Gwendal Roué via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

What about nothing?

let partial1 = f(arg1: 1, arg2:)
Gwendal

Le 2 févr. 2016 à 19:26, Gwendal Roué <gwendal.roue@gmail.com <mailto:gwendal.roue@gmail.com>> a écrit :

Any operator character would be bad, since the function may accept it, as in `[1,2,3].reduce(1, combine: *)`

Gwendal

Le 2 févr. 2016 à 19:24, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Feb 2, 2016, at 11:20 AM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On Feb 2, 2016, at 10:16 AM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

One superficial comment on this: the use of _ here is a bad idea. _ already means something in expressions - “discard”, and a closely related thing in declarations - “ignore”.

Adding a third very different thing (placeholder to be filled in later) seems like a really confusing thing to do.

-Chris

#?

# means “macro like” or “compiler synthesized”.

-Chris

* would be bad, right? And naked ?-marks?

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Joe Groff) #20

Not a super scientific study, but if you google "scala underscore", several of the results on the first page indicate confusion or bewilderment:

Scala _ [underscore] magic · Anantha Kumaran <https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwj-08ju59nKAhWj26YKHRuVBh8QFggdMAA&url=http%3A%2F%2Fananthakumaran.in%2F2010%2F03%2F29%2Fscala-underscore-magic.html&usg=AFQjCNEbIIoppVNYAjr6wqxL4byR9I1fAw&sig2=Hlw6hEFfsPqvlDvEFaDoyQ>

What are all the uses of an underscore in Scala? - Stack ... <https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0ahUKEwj-08ju59nKAhWj26YKHRuVBh8QFggjMAE&url=http%3A%2F%2Fstackoverflow.com%2Fquestions%2F8000903%2Fwhat-are-all-the-uses-of-an-underscore-in-scala&usg=AFQjCNHVNCJVosr0IzZYmh8pJRdnXTnf6g&sig2=vqWgzaddf2kEkWrdgFQuoQ&bvm=bv.113034660,d.dGY>

Scala dreaded underscore - SlideShare <https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=0ahUKEwj-08ju59nKAhWj26YKHRuVBh8QFggqMAI&url=http%3A%2F%2Fwww.slideshare.net%2Fnormation%2Fscala-dreaded&usg=AFQjCNEs5fGA4e8NsU10--FKfOyga8aEaA&sig2=mlWWAnJgFVxSpA4UtA2wyw>

underscore confusion | The Scala Programming Language <http://www.scala-lang.org/old/node/2916.html>

-Joe

···

On Feb 2, 2016, at 11:14 AM, Matthew Johnson <matthew@anandabits.com> wrote:

I know there is concern about overloading the semantics of `_` which is unfortunate as IMO it is the best symbol to serve as a placeholder. I wonder if there has been confusion about the semantics in practice in languages like Scala where it is used in both ways. Is there any evidence that this has been a problem?