Search code examples
iosswiftfunctional-programmingfunction-composition

Compiler error when using function composition: Cannot convert value of type `([Character]) -> String` to expected > argument type `_ -> _`


I am playing around with the custom operator >>> for function composition that is suggested here.

I have defined the following:

infix operator >>> { associativity left }
func >>> <A, B, C>(f: B -> C, g: A -> B) -> (A -> C) {
    return { x in f(g(x)) }
}

func toChars(s: String) -> [Character] {
    return s.characters.reduce([]) { (acc, c) in acc + [c] }
}

func myReverse(xs: [Character]) -> String {
    if let (head, tail) = xs.decompose {
        return String(myReverse(tail)) + String(head)
    }
    return ""
}

Now, when I want to put together those two functions like this:

func reverseString(s: String) -> String {
    return myReverse >>> toChars
}

I am getting the compiler error:

Cannot convert value of type ([Character]) -> String to expected argument type _ -> _.

According to my understanding this should work. >>> is defined to take two functions f : B -> C and g : A -> B. Looking at the structure of my usage, the following becomes clear:

  • g in this case is toChar : String -> [Character], so A is String and B is [Character]

  • f in this case is myReverse : [Character] -> String, so B is [Character] and C is String

This matches the type definitions form above, however I am still getting a compiler error. Does anyone know what I am doing wrong? Is there a syntax issue with the code?

Note, I am using an Array extension where the function decompose is defined like so:

var decompose : (head: Element, tail: [Element])? {
    if count > 0 {
        return (self[0], Array(self[1..<count]))
    }
    return nil
}

Solution

  • myReverse >>> toChars returns a closure of type String -> String, you still have to call the closure with a string argument:

    func reverseString(s: String) -> String {
        return (myReverse >>> toChars)(s)
    }
    

    But what you probably want is:

    let reverseString = myReverse >>> toChars
    

    In both cases, reverseString has the type String -> String, so you can call it as

    print(reverseString("foo"))
    // oof