-->

Swift higher order function (Church pair aka cons)

2020-03-26 01:42发布

问题:

I was messing around with the functional programming in Swift 2.1, trying to implement the Church encoding pair/cons function (cons = λx λy λf f x y in untyped lambda calculus), which I had read couldn't be done in earlier versions of Swift.

With generics it looks like

func cons<S,T,U>(x:S,_ y:T) -> ((S,T) -> U) -> U
{
    return { (f:((S,T) -> U)) -> U in return f(x,y)}
}

cons(1,2)
//error: cannot invoke 'cons' with an argument list of type '(Int, Int)'
//note: expected an argument list of type '(S, T)'

which doesn't work, and gives an error I cannot understand (surely parameter list of type (Int,Int) can match generic type variables (S,T)?)

If you get rid of the generic types, and declare them all Ints, the function works, but of course we want to be able to cons together lists longer than 2; consing a list of length 3 is consing an Int with an (Int,Int) -> Int, for example.

Another option is to type everything as Any (see Type Casting for Any and AnyObject), but I couldn't make that work either.

Do you have any ideas? Is this possible in Swift yet? I'm sure there are simpler ways to implement cons/car/cdr, but I'm specifically interested in the Church encoding, where the list elements are arguments to anonymous functions (lambdas).

回答1:

func cons<S,T,U>(x:S,_ y:T) -> ((S,T) -> U) -> U
{
    return { (f:((S,T) -> U)) -> U in return f(x,y)}
}

let i: ((Int,Int)->Int)->Int = cons(1,2)
let d: ((Int,Int)->Double)->Double = cons(2,3)
let e: ((Double,Int)->String)->String = cons(2.2, 1)
let e: ((Double,Int)->Double)->Double = cons(2.2, 1)

stil one of type is an 'extra' type and could not be inferred by compilator. if you define the types, you can see, that not all combinations are valid. Just define the output type and the compilator should be happy

func cons<S,T, U>(x:S,_ y:T, outptAs: U.Type) -> ((S,T) -> U ) -> U
{
    return { (f:((S,T) -> U)) -> U in return f(x,y) }
}

let i = cons(1.2 ,"A", outptAs: Int.self)
let j = cons("alfa","beta", outptAs: Double.self)