双通用数据结构上的flatMap如何显示?

时间:2016-01-15 00:57:23

标签: swift functional-programming monads flatmap

我有以下(简单)数据结构:

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

此类型表示可以将Input转换为所需Output的作品。我试图看看这个数据结构是否符合函数概念,如仿函数或monad。

函子

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的{​​{1}}(或fold)函数的定义。我能想出的唯一一件事就是:

Work

如果你在swift中查找extension Work { func flatMap<MoreOutput>(transform: Work<Output, MoreOutput>) -> Work<Input, MoreOutput> { return Work<Input, MoreOutput> { input in return transform.work(self.work(input)) } } } 的{​​{1}}定义,它看起来像这样(简化):

flatMap

这是一个函数,其参数是一个函数,它将Array转换为func flatMap(transform: (Element) -> T?) -> [T] 并生成Element。我想不出将其抽象为T类型的方法。

从另一本功能书中我发现了flatMap的一般定义如下(在一个对象Array上持有Work}:

F

A的定义与func flatMap<B>(f: A -> F<B>) -> F<B> 似乎不同。

有人可以向我解释这个差异吗?甚至可以定义一个正确的&#39; flatMap上的Array功能?或flatMap不满足Monad属性?

** 修改

感谢phg提供了这么多有用的信息。我尝试过Profunctor定义:

使Work成为Work

Work

这看起来对你好吗?

1 个答案:

答案 0 :(得分:1)

此:

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

是你想要flatMap的样子;这是monad的惯常"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?意味着&#34;可选T&#34;或者&#34;可以为T&#34;。这不是我们通常所理解的monadic函数,但它是相关的。事实上,a question关于这种&#34;广义的flatMaps&#34;。答案是,如果两个monad是兼容的,即存在 monad morphism F<A> -> G<A>保留monadic结构,那么定义

是有意义的
func wrappedFlatMap<B>(f: A -> F<B>) -> G<B>

这可能就是&#34;选项类型&#34;正好发生的事情。和列表类型,其中态射在逻辑上只是

Just x ~> [x]
Nothing ~> []