2 posts tagged

functor

Апликативные функторы

В отличие от обычных функторов, у апликативных функторов функция так же упакована в контекст как и значения к которым она будет применяться. По дефолту в свифте нет апликативных функторов, но можно легко добавить самому, например для типа Optional добавим функцию apply, которая знает как применить функцию, обернутую в контекст к значениям, которые обернуты в тот же контекст.

extension Optional {
  func apply<U>(f: (Wrapped -> U)?) -> U? {
    switch f {
      case .Some(let someF): return self.map(someF)
      case .None: return .None
    }
  }
}

Теперь можно взять функцию сложения plusTwoNumbers из предыдущего поста об функторах и что-бы применить ее к значению, нужно обернуть в тот же контекст Optional и передать функции apply:

let plus = plusTwoNumbers(5)
Optional.Some(10).apply(Optional.Some(plus))
// => .Some(15)

Или для удобства написать свой оператор:

infix operator <*> { associativity left }

func <*><T, U>(f: (T -> U)?, a: T?) -> U? {
  return a.apply(f)
}

Optional.Some(plus) <*> Optional.Some(10)
// => .Some(15)
2016   applicatives   functor   Swift

Функторы

Функтор – это такой клас типов, которые реализуют функцию map. Это некий контейнер, к элементам которого можно применить функцию и в результате получить новый точно такой же контейнер (структура остается неизменной), но с новыми елементами. Иными словами, функтор применяет функцию к значениям, которые он содержит, а не к себе.

Функтором является тип Optional а также все последовательние типи в свифте: Dictionary, Array и Set.

К примеру, обычное сложение с использованием функтора будет выглядеть так:

func plusTwoNumbers(firstNumber: Int) -> (Int)-> Int {
    return { (secondNumber: Int) -> (Int) in
        return firstNumber + secondNumber
    }
}
let plus = plusTwoNumbers(5)
Optional.Some(10).map(plus)
// => .Some(15)

Функтор определяет, как будет будет реализована функция map и поскольку Optional это функтор, то у него есть своя реализация:

func map<U>(f: T -> U) -> U? {
  switch self {
  case .Some(let x): return f(x)
  case .None: return .None
}

Получается, что если мы в начале имеем None, то и в результате также будет иметь None. В случае с языками, которые не имеют опциональных типов, приходится делать проверку:

let user = Users.findByID(1)
if user != nil {
  return user.name
} else {
  return nil
}

Когда в свифте с исплозованием функтора Optional тоже самое можно сделать проще:

findByID(1).map(getUserName)
2016   functor   Swift