双泛型数据结构上的 flatMap 是什么样子的?
How does a flatMap on a double-generic data-structure looks like?
我有以下(简单的)数据结构:
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([=11=]))
}
}
}
据我所知,这似乎是正确的。我能够编写一个映射函数,它可以将 Work<Input, Output>
变成 Work<Input, MoreOutput>
单子
我很难想到Work
的flatMap
(或fold
)函数的定义。我唯一能想到的是:
extension Work {
func flatMap<MoreOutput>(transform: Work<Output, MoreOutput>) -> Work<Input, MoreOutput> {
return Work<Input, MoreOutput> { input in
return transform.work(self.work(input))
}
}
}
如果您在 swift 中查找 Array
的 flatMap
定义,它看起来像这样(简化):
func flatMap(transform: (Element) -> T?) -> [T]
这是一个函数,其参数是将 Element
转换为 T
并生成 Array
的函数。我想不出一种方法将其抽象为 Work
类型。
我从另一本功能性书籍中找到了 flatMap 的一般定义如下(在持有类型 A
的对象 F
上):
func flatMap<B>(f: A -> F<B>) -> F<B>
flatMap
的定义似乎与 Array
的定义不同。
谁能给我解释一下这个区别?甚至可以在 Work
上定义 'correct' flatMap
函数吗?或者 Work
不满足成为 Monad 的属性?
** 编辑
感谢 phg 提供这么多有用的信息。我试过做 Profunctor 定义:
制作Work
一个Profunctor
:
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)
}
}
}
你觉得这样对吗?
这个:
func flatMap<B>(f: A -> F<B>) -> F<B>
就是你想要flatMap
的样子;这是 monad 通常的 "bind" operation. Specialized for functions over the second argument, you get the so-called 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([=11=])).work([=11=])
}
}
}
注意:我实际上不会说 Swift,这段代码只是猜测——因此包含 Haskell 原文。请随意编辑更正后的版本。
现在进入另一个定义:
func flatMap(transform: (Element) -> T?) -> [T]
我想 T?
的意思类似于 "optional T
" 或 "nullable T
"。这不是我们通常理解的monadic function,但它是相关的。的确,关于这样的"generalized flatMaps"已经有a question了。答案是,如果两个 monad 兼容,即存在 monad morphism F<A> -> G<A>
保留 monadic 结构,定义
是有意义的
func wrappedFlatMap<B>(f: A -> F<B>) -> G<B>
这可能正是 "option type" 和列表类型在这里发生的情况,其中态射在逻辑上只是
Just x ~> [x]
Nothing ~> []
我有以下(简单的)数据结构:
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([=11=]))
}
}
}
据我所知,这似乎是正确的。我能够编写一个映射函数,它可以将 Work<Input, Output>
变成 Work<Input, MoreOutput>
单子
我很难想到Work
的flatMap
(或fold
)函数的定义。我唯一能想到的是:
extension Work {
func flatMap<MoreOutput>(transform: Work<Output, MoreOutput>) -> Work<Input, MoreOutput> {
return Work<Input, MoreOutput> { input in
return transform.work(self.work(input))
}
}
}
如果您在 swift 中查找 Array
的 flatMap
定义,它看起来像这样(简化):
func flatMap(transform: (Element) -> T?) -> [T]
这是一个函数,其参数是将 Element
转换为 T
并生成 Array
的函数。我想不出一种方法将其抽象为 Work
类型。
我从另一本功能性书籍中找到了 flatMap 的一般定义如下(在持有类型 A
的对象 F
上):
func flatMap<B>(f: A -> F<B>) -> F<B>
flatMap
的定义似乎与 Array
的定义不同。
谁能给我解释一下这个区别?甚至可以在 Work
上定义 'correct' flatMap
函数吗?或者 Work
不满足成为 Monad 的属性?
** 编辑
感谢 phg 提供这么多有用的信息。我试过做 Profunctor 定义:
制作Work
一个Profunctor
:
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)
}
}
}
你觉得这样对吗?
这个:
func flatMap<B>(f: A -> F<B>) -> F<B>
就是你想要flatMap
的样子;这是 monad 通常的 "bind" operation. Specialized for functions over the second argument, you get the so-called 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([=11=])).work([=11=])
}
}
}
注意:我实际上不会说 Swift,这段代码只是猜测——因此包含 Haskell 原文。请随意编辑更正后的版本。
现在进入另一个定义:
func flatMap(transform: (Element) -> T?) -> [T]
我想 T?
的意思类似于 "optional T
" 或 "nullable T
"。这不是我们通常理解的monadic function,但它是相关的。的确,关于这样的"generalized flatMaps"已经有a question了。答案是,如果两个 monad 兼容,即存在 monad morphism F<A> -> G<A>
保留 monadic 结构,定义
func wrappedFlatMap<B>(f: A -> F<B>) -> G<B>
这可能正是 "option type" 和列表类型在这里发生的情况,其中态射在逻辑上只是
Just x ~> [x]
Nothing ~> []