关于swift:双通用数据结构上的flatMap看起来如何?

How does a flatMap on a double-generic data-structure looks like?

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

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

此类型表示可以占用Input并变成所需的Output的作品。我正在尝试查看此数据结构是否符合某些功能性概念,例如函子或monad。

函子

1
2
3
4
5
6
7
extension Work {
    func map<MoreOutput>(transform: Output -> MoreOutput) -> Work<Input, MoreOutput> {
        return Work<Input, MoreOutput> {
            return transform(self.work($0))
        }
    }
}

据我所知,这似乎是正确的。我能够编写一个映射函数,该函数可以将Work转换为Work

单子

我很难想到WorkflatMap(或fold)函数的定义。我唯一能想到的是以下内容:

1
2
3
4
5
6
7
extension Work {
    func flatMap<MoreOutput>(transform: Work<Output, MoreOutput>) -> Work<Input, MoreOutput> {
        return Work<Input, MoreOutput> { input in
            return transform.work(self.work(input))
        }
    }
}

如果快速查找ArrayflatMap定义,则它看起来像这样(简化):

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

这是一个函数,其参数是将Element转换为T并生成Array的函数。我想不出一种将其抽象为Work类型的方法。

从另一本功能书籍中,我发现了flatMap的通用定义,如下所示(在对象F上,类型为A):

1
func flatMap(f: A -> F) -> F

flatMap的定义不同于Array的实现。

有人可以向我解释这种差异吗?甚至有可能在Work上定义"正确的" flatMap函数吗?还是Work不满足成为Monad的属性?

**编辑

感谢phg提供了许多有用的信息。我试图做Profunctor的定义:

Work设为Profunctor

1
2
3
4
5
6
7
8
9
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(f: A -> F) -> F

您要的flatMap看起来是什么? 这是monad通常的"绑定"操作。 专门针对第二个参数的函数,您得到了所谓的Reader monad:

1
2
3
4
5
6
7
8
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原始文档。 随时以更正的版本进行编辑。

现在到另一个定义:

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

我想T?的意思是"可选T"或"可空T"。 这不是我们通常理解的单子函数,但它是相关的。 确实,关于这种"广义flatMaps"存在疑问。 答案是,如果两个monad兼容,即存在一个保留monadic结构的monad态射F -> G,则定义

1
func wrappedFlatMap(f: A -> F) -> G

这可能正是这里的"选项类型"和列表类型正在发生的情况,其中态射在逻辑上只是

1
2
Just x ~> [x]
Nothing ~> []