I want to write a flip method in Swift.
Here is the signature.
Prelude> :t flip
flip :: (a -> b -> c) -> b -> a -> c
My code in Swift:
func flip1<A, B, C>(f: A->B->C) -> (B->A->C) {
return { (valueB: B, valueA: A) in
return f(valueA, valueB)
}
}
func flip2<A, B, C>(f: A->B->C) -> (B->A->C) {
return { (valueB: B) in
return { (valueA: A) in
return f(valueA)(valueB)
}
}
}
The flip1 method can not compile. There is an error Extra argument in call at line return f(valueA, valueB)
The flip2 method works fine, except the flipped method can only be called like this method(1)(2).
How to write the flip method so that I can use the flipped method like method(1, 2) and method(1)(2)?
A->B->C is the type of a function taking one argument of type A
and returning a function B->C (a "curried" function). The type of a function taking
two arguments is (A, B)->C:
func flip<A, B, C>(f: (A, B)->C) -> (B, A)->C {
return { (valueB: B, valueA: A) in
return f(valueA, valueB)
}
}
let x = flip(-)(10, 5)
println(x) // -5
It can slightly be shortened to
func flip<A, B, C>(f: (A, B)->C) -> (B, A)->C {
return { (valueB, valueA) in
f(valueA, valueB)
}
}
due to automatic type inference.
As far as I know, Swift does not automatically convert functions
taking multiple arguments into curried functions, compare
Typecase regular Swift function to Curry Function.
This is the #MartinR answer updated to Swift 5.1
func flip<A, B, C>(_ f: #escaping (A, B)->C) -> (B, A)->C {
return { (valueB: B, valueA: A) in
return f(valueA, valueB)
}
}
let x = flip(-)(10, 5) println(x) // -5
It can slightly be shortened to
func flip<A, B, C>(_ f: #escaping (A, B)->C) -> (B, A)->C {
{ (valueB: B, valueA: A) in
f(valueA, valueB)
}
}
Related
In the below example, why is the foo(f) call ambiguous?
I understand that the second overload could also apply with P == (),
but why isn't the first one considered more specialized,
and therefore a better match?
func foo<R>(_ f: () -> R) { print("r") }
func foo<P, R>(_ f: (P) -> R) { print("pr") }
let f: () -> Int = { 42 }
foo(f) // "Ambiguous use of 'foo'"
I'd say your problem is that you don't explicitely tell the compiler that P == ()
try the following code in a playground :
Void.self == (Void).self // true
Void() == () // true
(Void)() == () // true
(Void) == () // Cannot convert value of type '(Void).Type' to expected argument type '()'
Foo<Int>.self == (() -> Int).self // false
(() -> Int).self == ((Void) -> Int).self // false
Foo<Int>.self == ((Void) -> Int).self // true
Since (Void) cannot be converted to (), I guess the compiler can't understand that foo<R>(_ f: () -> R) is actually a specialization of foo<P, R>(_ f: (P) -> R).
I suggest you create generic type aliases for your function types to help the compiler understand what you're doing eg. :
typealias Bar<P, R> = (P) -> R
typealias Foo<R> = Bar<Void, R>
Now you can can define your function like that :
func foo<R>(_ f: Foo<R>) { print("r") } // Note that this does not trigger a warning.
func foo<P, R>(_ f: Bar<P, R>) { print("pr") }
and then use them with any closure you want :
let f: () -> Int = { 42 }
foo(f) // prints "r"
let b: (Int) -> Int = { $0 }
foo(b) // prints "pr"
let s: (String) -> Double = { _ in 0.0 }
foo(s) // prints "pr"
But you can actually just write :
func foo<R>(_ f: (()) -> R) { print("r") }
func foo<P, R>(_ f: (P) -> R) { print("pr") }
or even :
func foo<R>(_ f: (Void) -> R) { print("r") } // triggers warning :
// When calling this function in Swift 4 or later, you must pass a '()' tuple; did you mean for the input type to be '()'?
func foo<P, R>(_ f: (P) -> R) { print("pr") }
and you get the same results.
I need to write a function that swaps the contents of any two variables. This is what I have currently but I am getting the error "Cannot assign to value: 'a' is a 'let' constant".
func swap<T>(a: T, b: T) {
(a, b) = (b, a);
}
Can somebody please explain why this doesn't work and suggest how to fix it?
Thank you.
You need to make the parameters inout to be able to do that, like this:
func swap<T>(_ a: inout T,_ b: inout T) {
(a, b) = (b, a)
}
var a = 0, b = 1
swap(&a, &b)
The parameters inside your function is immutable so it cannot be swapped , like if you trying to swap two let value:
let x = 5
let y = 6
//if you try to swap these values Xcode will tell you to change their declaration to var
Here almost the same and to be able to change the values you have to pass inout declaration like below :
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
(a, b) = (b, a)
}
// call it like this
var x = 1
var y = 2
swapTwoValues(&x, &y)
// Note that you cannot call it like this: swapTwoValues(&1, &2)
That is because the arguments of functions are constants and are treated as local properties, unless you mark them inout and then they are treated as sort of "pass-through" properties that aren't confined to the scope of the function.
var kiwi = "kiwi"
var mango = "mango"
func swap<T>(a: inout T, b: inout T) {
(a, b) = (b, a)
}
swap(&kiwi, &mango)
If having to put & everywhere or the verbosity of the function annoy you, you could always use a descriptive operator like this:
infix operator <->: AssignmentPrecedence
func <-> <A>(lhs: inout A, rhs: inout A) {
(lhs, rhs) = (rhs, lhs)
}
var kenobi = "Hello there!"
var helloThere = "Kenobi..."
helloThere <-> kenobi
print(helloThere, kenobi, separator: "\n")
// Hello there!
// Kenobi...
Which I feel looks much nicer. You don't need to use & in operators with inout parameters – that's how the += and -= operators work:
public extension AdditiveArithmetic {
static func +=(lhs: inout Self, rhs: Self) {
lhs = lhs + rhs
}
static func -=(lhs: inout Self, rhs: Self) {
lhs = lhs - rhs
}
}
please, check my snippet, the question is there (my english is too bad to be able to explain my trouble by the words :))
func flip1<A, B, C>(f : ((A, B) -> C), _ b : B, _ a : A) -> C {
return f(a, b)
}
flip1(-, 2, 1) // -1
flip1(/, 2.0, 3.0) // 1.5
// partialy curried version
func flip2<A, B, C>(f : (A, B) -> C, _ i : B, _ j : A) -> C {
return f(j, i)
}
print(flip2(- , 2, 1)) // -1
print(flip2(/,2.0,3.0)) // 1.5
compiles without trouble, but how to use it???
// full curried version
// compiles without trouble, but how to use it???
func flip3<A, B, C>(f : A -> B -> C) -> B -> A -> C {
return { b in { a in f(a)(b) } }
}
/*
* flip3(/)(2.0)(3.0)
*
* error: ambiguous reference to member '/'
* it meands there are more than one candidate for / function
*/
// we need curried version of /, let's define it
func curry<A,B,C>(f: (A, B) -> C) -> A -> B -> C {
return { a in { b in f(a, b) } }
}
/*
* let divideUnknownType = curry(/)
* compiler still complain, as expected :-)
* error: ambiguous use of operator '/'
*/
// and then define the type of it
let divideDoubles: Double->Double->Double = curry(/)
let divideIntegers: Int->Int->Int = curry(/)
// :-)
print(flip3(divideDoubles)(2.0)(3.0)) // 1.5
print(flip3(divideDoubles)(2)(3)) // 1.5
print(flip3(divideIntegers)(2)(3)) // 1
as you can see, it breaks my 'generic' approach. any idea how to solve it?
func flip3<A, B, C>(f: (A, B) -> C) -> B -> A -> C {
return { b in { a in f(a, b) } }
}
flip3(/)(2.0)(3.0) // 1.5
While trying to implement a simple lazy list in Swift, I tried creating an extension for enum in Swift, with a generic method inside (emulating a type class-like behavior, as I'm trying out Swift while being a Scala developer most of the time), like so:
enum LazyList<A>{
case Elem(x: A, xs: () -> LazyList<A>)
case Nil()
}
extension LazyList {
func map<B>(f: (A) -> B) -> LazyList<B> {
func lazyMap(l: LazyList<A>, lf: (A) -> B) -> LazyList<B> {
switch l {
case let .Elem(e, es):
return LazyList.Elem(x: lf(e), xs: {() -> LazyList<B> in return lazyMap(es(), lf: lf)})
case .Nil:
return LazyList.Nil()
}
}
return lazyMap(self, lf: f)
}
}
This however does not run in the playground, failing to compile with error below:
error: cannot convert value of type 'LazyList<A>' to expected argument type 'LazyList<_>'
return LazyList.Elem(x: lf(e), xs: {() -> LazyList<B> in return lazyMap(es(), lf: lf)})
How can I get it to compile? Is it because the compiler cannot infer the return type of lazyMap?
simply remove the "LazyList." from your switch cases :)
enum LazyList<A>{
case Elem(x: A, xs: () -> LazyList<A>)
case Nil()
}
extension LazyList {
func map<B>(f: (A) -> B) -> LazyList<B> {
func lazyMap(l: LazyList<A>, lf: (A) -> B) -> LazyList<B> {
switch l {
case let .Elem(e, es):
return .Elem(x: lf(e), xs: {() -> LazyList<B> in return lazyMap(es(), lf: lf)})
case .Nil:
return .Nil()
}
}
return lazyMap(self, lf: f)
}
}
I was going through this blog. When I tried write curry function on my own method:
func stdCurry(f : (A,B) -> C) -> (A)->(B->C) {
return { (a:A) ->(B -> C) in {
(b:B) -> C in
{
return f(a,b)
}
}
}
}
I got an error:
:7:22: error: declared closure result 'C' is incompatible with contextual type '_'
(b:B) -> C in
^
_
But when I remove the flower parentheses around trailing closure then it won't report any error. Can anybody help me to understand this.
The inner curly braces -> in { ... } tells swift that this inner part is a closure, whereas it in fact only contains a value (the C type evaluation of f(a,b)). If you remove these inner curly braces, your example work.
E.g., try
func stdCurry<A,B,C>(f : (A,B) -> C) -> (A) -> (B -> C) {
return { (a:A) -> (B -> C) in {
(b:B) -> C in
return f(a,b) // <-- this is not a closure (just returns a value of type C`
}
}
}
Note that I've added the generic types to the function signature above (perhaps you function is part of a class and you get your types A, B and C from there).
To make the error above more clear, consider this a bit simpler example (taking a closure and returning it):
/* This is ok */
func myClosure<A,B>(f: (A) -> B) -> (A) -> B {
return {
x in f(x)
}
}
/* Error: return type here is not (A) -> B, but contains
an anonymous closure () -> B */
func myClosure<A,B>(f: (A) -> B) -> (A) -> B {
return {
x in { f (x) }
}
}
/* Ok */
func myClosure<A,B>(f: (A) -> B) -> (A) -> (() -> B) {
return {
x in { f(x) }
}
}
Also note that since Swift knows (infers)---from your function signature---the types in as well as what type/closure to expect in return for each in ... statment, you can omit the closure type ((a:A) -> (B -> C)) as well as the return keyword and make your expression more compact as follows:
func stdCurry<A, B, C>(f: (A, B) -> C) -> A -> (B -> C) {
return { a in { b in f(a, b) } }
}
At your request in the comments below: you can make use of "multiple statements" in the tail e.g. by using the approach of the third "simple example" above, e.g.:
func stdCurry<A,B,C>(f : (A,B) -> C) -> (A) -> (B) -> () -> C {
return { (a:A) -> (B -> () -> C) in {
(b:B) -> () -> C in
return {
// ...
f(a,b)
}
}
}
}
Note that as the function signature grows somewhat "messy", it's favourable to omit these details in the actual closures of your function, i.e.:
func stdCurry<A,B,C>(f : (A,B) -> C) -> (A) -> (B) -> () -> C {
return { a in {
b in
return {
// ...
f(a,b)
}
}
}
}