skip to Main Content

Recently I’m learning functional programing using swift programing language, and found a library named Swiftz, I found a very strange way to call function and would like to ask if anyone knows why it works, thanks!

Simple code here, Person().walk <*> 10 is too wired for me, before <*> and after <*> are whitespaces but no error occurred🤔.

import Swiftz

class Person {
    func walk(step: Int) {
        print("walk (step) step")
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        Person().walk <*> 10
        // ⬇️ normal way for same result
        // Person().walk(step: 10)
    }
}

// print result: walk 10 step

I try to found the <*> code in Swiftz, but It’s not clear for reason.

public func <*> <A, B>(f : ((A) -> B)?, a : A?) -> B? {
    return f.flatMap { $0 <^> a }
}

2

Answers


  1. <*> is an operator defined in this library.

    <A, B> means the operator definition has two types as parameters, referred to as A and B.

    The operator has two arguments f and a for the left hand and right hand side. In your example, f is Person().walk, and a is 10. And it returns an optional B, where B is the type that Person.walk would return if you call it.

    f is an optional function taking A as a parameter and returning B. In your case, walk takes an Int parameter and returns Void, so A is Int and B is Void. And the right hand side was supposed to be A?, which is fine since 10 is of type Int.

    And then it calls another operator that you need to examine. Important is: That operator takes any function on the left hand side that has one argument of type A, and a value on the right hand side with type A?, and returns whatever the function would have returned.

    Login or Signup to reply.
  2. Person().walk is a function – (Int) -> Void, and 10 is an Int. What <*> does is function application – it applies the left operand to the function that is the right operand. In other words, it calls the function on its right with the thing on its left as an argument. It’s just that both the function and its argument can be optional (note the ?s in the signature). This is kind of like Haskell’s <*>, but specifically for Maybe (Optional‘s Haskell counterpart).

    If you remove all the optional-handling:

    public func <*> <A, B>(f : ((A) -> B), a : A) -> B {
        return f(a)
    }
    

    Yep, that’s what it does (plus handling the optionals)!

    The optional handling isn’t that hard to understand either. $0 <^> a just means a.map($0). Both flatMap. These are built in Swift functions. If you don’t understand how they work, read this. Ultimately what it does is if either f or a is nil, <*> returns nil too.

    Now you might be wondering why we need this function at all. Well, making "apply this function" itself a function means that we can pass it around to other functions, compose it with other functions!

    However, I don’t think this works in Swift as well as it does in Haskell. In Swift, the compiler needs to be able to infer every type parameter to a known type, which can make many things that you can easily do in Haskell, difficult and cumbersome.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search