Description
It's annoying when I can't write a function point-free style just because I cannot partially apply the second argument of a 2-ary function (or more generally, the ith parameter of an n-ary). For example, we need the lift function in Functor just because we can't partially apply the function in map in a convenient and easy way.
I propose a new syntax for partial application that extends the current one to allow partial application of any parameters in a function.
Sample usage
I propose to add a new operator <|, that takes a function as first argument and a tuple with values and placeholders as second argument. The placeholders (a placeholder is two underscores) help determine what parameter a value is being applied to.
For partial application of the first parameter, we can also keep the current simplified syntax.
let f: (String, Int) -> Int = { s, i in i }
// Partially apply first argument
let p1CurrentSyntax /* : (Int) -> Int */ = f <| "a"
let p1NewSyntax /* : (Int) -> Int */ = f <| ("a", __)
// Partially apply second argument
let p2 /* : (String) -> Int */ = f <| (__, 1)
Note how I've written the resulting function type in comments, meaning that type inference works well with the syntax.
I chose to reverse the direction and parameter position of the current |> because now the position of the function and the tuple of arguments resembles the order in which you normally write function application.
Potential implementation
The trick is to define a special PlaceHolder type just so we can write .__ on our tuples.
If we also define __ as a global value we can avoid the leading dot. This is not needed (type inference also works if we write .__). It makes the syntax nicer, but it pollutes the global namespace. What do you think?
public enum PlaceHolder {
case __
}
public let __ = PlaceHolder.__
infix operator <| : AdditionPrecedence
// Support for simplified syntax for partial application of the first parameter
public func <|<A, B, C>(_ f: @escaping (A, B) -> C, _ value: A) -> (B) -> C {
{ b in f(value, b)}
}
public func <|<A, B, C>(_ f: @escaping (A, B) -> C, _ values: (PlaceHolder, B)) -> (A) -> C {
{ a in f(a, values.1)}
}
public func <|<A, B, C>(_ f: @escaping (A, B) -> C, _ values: (A, PlaceHolder)) -> (B) -> C {
{ b in f(values.0, b)}
}
// ... implementations for higher arities
Modules
Bow
Breaking changes
None, unless we remove |>.
Description
It's annoying when I can't write a function point-free style just because I cannot partially apply the second argument of a 2-ary function (or more generally, the ith parameter of an n-ary). For example, we need the
liftfunction inFunctorjust because we can't partially apply the function inmapin a convenient and easy way.I propose a new syntax for partial application that extends the current one to allow partial application of any parameters in a function.
Sample usage
I propose to add a new operator
<|, that takes a function as first argument and a tuple with values and placeholders as second argument. The placeholders (a placeholder is two underscores) help determine what parameter a value is being applied to.For partial application of the first parameter, we can also keep the current simplified syntax.
Note how I've written the resulting function type in comments, meaning that type inference works well with the syntax.
I chose to reverse the direction and parameter position of the current
|>because now the position of the function and the tuple of arguments resembles the order in which you normally write function application.Potential implementation
The trick is to define a special
PlaceHoldertype just so we can write.__on our tuples.If we also define
__as a global value we can avoid the leading dot. This is not needed (type inference also works if we write.__). It makes the syntax nicer, but it pollutes the global namespace. What do you think?Modules
Bow
Breaking changes
None, unless we remove
|>.