2016-01-15 1 views
0

У меня есть следующие (простые) структуры данных:Как выглядит flatMap в структуре данных с двумя генериками?

struct Work<Input, Output> { 
    let work: Input -> Output 
} 

Этого типа представляет работу, которая может принимать Input и превращает в в желаемом Output. Я пытаюсь понять, соответствует ли эта структура данных некоторым функциональным концепциям, таким как функтор или монада.

Functor

extension Work { 
    func map<MoreOutput>(transform: Output -> MoreOutput) -> Work<Input, MoreOutput> { 
     return Work<Input, MoreOutput> { 
      return transform(self.work($0)) 
     } 
    } 
} 

Это кажется правильным, насколько мне известно. Я могу написать функцию карты, которая может превратить Work<Input, Output> в Work<Input, MoreOutput>

Монады

у меня есть проблема мышления определения для функции flatMap (или fold) для Work. Единственное, что я могу придумать следующий:

extension Work { 
    func flatMap<MoreOutput>(transform: Work<Output, MoreOutput>) -> Work<Input, MoreOutput> { 
     return Work<Input, MoreOutput> { input in 
      return transform.work(self.work(input)) 
     } 
    } 
} 

Если вы заметили flatMap определение для Array в стрижа это выглядит так (упрощенно):

func flatMap(transform: (Element) -> T?) -> [T] 

Это функция где его аргумент является функцией, которая преобразует Element в T и приводит к Array. Я не могу придумать способ абстрагирования этого типа Work.

С другой функциональной книге я нашел общее определение flatMap следующим образом (на объект F типа удерживания A):

func flatMap<B>(f: A -> F<B>) -> F<B> 

который представляет собой другое определение flatMap, чем кажется Array реализовать.

Может кто-нибудь объяснить эту разницу мне? И можно ли даже определить «правильную» функцию flatMap на Work? Или Work не удовлетворяет свойствам Монады?

** Редактировать

Благодаря PHG так много полезной информации. Я пытался сделать определение Profunctor:

Изготовление WorkProfunctor:

extension Work { 
    func diMap<A, B>(fa: A -> Input, fb: Output -> B) -> Work<A, B> { 
     return Work<A, B> { arg in 
      let input = fa(arg) 
      let output = self.work(input) 
      return fb(output) 
     } 
    } 
} 

это выглядит прямо к вам?

ответ

1

Это:

func flatMap<B>(f: A -> F<B>) -> F<B> 

является то, что вы хотите flatMap выглядеть; это обычная монада "bind" operation.Специализированный для функций над вторым аргументом, вы получаете так называемый Reader monad:

extension Work { 
    func flatMap<MoreOutput>(g: Output -> Work<Input, MoreOutput>) -> Work<Input, MoreOutput> { 
     // (Reader f) >>= g = Reader $ \x -> runReader (g (f x)) x 
     return Work<Input, MoreOutput> { 
      g(self.work($0)).work($0) 
     } 
    } 
} 

Примечания: Я на самом деле не говорить Swift, этот код был только гадать - значит включен Haskell оригинала. Не стесняйтесь редактировать в исправленной версии.


Теперь к другому определению:

func flatMap(transform: (Element) -> T?) -> [T] 

Я полагаю T? означает что-то вроде "необязательной T" или "обнуляемого T". Это не то, что мы обычно понимаем как монадическую функцию, но это связано. Действительно, в таких «обобщенных плоских картах» было a question. Ответ в том, что если две монад совместимы, то есть, существует монады морфизмаF<A> -> G<A> сохранения монадической структуры, то имеет смысл определить

func wrappedFlatMap<B>(f: A -> F<B>) -> G<B> 

, который, вероятно, именно то, что происходит здесь «тип параметра "и тип списка, где морфизм логически просто

Just x ~> [x] 
Nothing ~> [] 
+0

О, и в то время как вы на него, вы можете сделать' Work' а [profunctor] (http://haddock.stackage.org/lts -4,1/profunctors-5.1.2/Data-Profunctor.html)! – phg

+0

Отлично, это много полезной информации! Отредактировал свой ответ, чтобы добавить мою первую попытку профессора в «Работа». –

Смежные вопросы