Functional programming 函子和单子有什么区别?
这里也有类似的问题,但它们都附加到一种特定的编程语言中,我正在寻找概念层面的答案 据我所知,函子本质上是不可变的容器,它公开了派生另一个函子的map()API。哪一个加法使得可以将特定的函子称为单子 据我所知,每个单体都是函子,但并非每个函子都是单体。(请注意,这将是对范畴论概念的简化解释) 函子 函子是从一组值A到另一组值的函数:Functional programming 函子和单子有什么区别?,functional-programming,monads,functor,Functional Programming,Monads,Functor,这里也有类似的问题,但它们都附加到一种特定的编程语言中,我正在寻找概念层面的答案 据我所知,函子本质上是不可变的容器,它公开了派生另一个函子的map()API。哪一个加法使得可以将特定的函子称为单子 据我所知,每个单体都是函子,但并非每个函子都是单体。(请注意,这将是对范畴论概念的简化解释) 函子 函子是从一组值A到另一组值的函数:A->b。对于编程语言,这可能是一个从String->Integer开始的函数: 函数fn(文本:字符串):整数 作文 组合是将一个函数的值用作下一个函数的值的输入:
A->b
。对于编程语言,这可能是一个从String->Integer
开始的函数:
函数fn(文本:字符串):整数
作文
组合是将一个函数的值用作下一个函数的值的输入:fa(fb(x))
。例如:
hash(小写(文本))
单子
单子允许组合不可组合的函子,或通过在组合中添加额外功能来组合函子,或两者兼而有之
- 第一个例子是函子
String->(String,Integer)
- 第二种方法的一个例子是对一个值调用的函数数进行计数的Monad
T
,它负责您想要的功能以及两个其他功能:
input->T(输入)
T(T(输入))->T(输入)
总之,每个单子都不是一个函子,而是用一个函子来完成它的目的。让我解释一下我的理解,不必进入范畴理论: 函子和单子都为包装输入提供了一些工具,返回包装输出 函子=单位+映射(即工具) 在哪里,
unit
=接收原始输入并将其封装在小上下文中的东西
map
=将函数作为输入,将其应用于包装器中的原始值,并返回包装结果的工具
示例:让我们定义一个将整数加倍的函数
// doubleMe :: Int a -> Int b
const doubleMe = a => 2 * a;
Maybe(2).map(doubleMe) // Maybe(4)
Monad=unit+flatMap(或bind或chain)
flatMap
=如其名称所示,用于展平贴图的工具。下面的例子很快就会清楚
示例:假设我们有一个curried函数,它只在两个字符串都不是空时才附加两个字符串
让我将其中一个定义如下:
append :: (string a,string b) -> Maybe(string c)
现在让我们看看map
(随Functor
附带的工具)的问题
为什么这里有两个可能s
嗯,这就是map
所做的;它将提供的函数应用于包装的值并包装结果
让我们把它分成几个步骤
将映射函数应用于包装值
; 这里映射的函数是append(“b”)
,包装的值是“a”
,这导致可能(“ab”)
包装结果,返回Maybe(Maybe(“ab”))
现在我们感兴趣的值被包装两次。下面是救援的flatMap
Maybe("a").flatMap(append("b")) // Maybe("ab")
当然,函子和单子也必须遵循一些其他规律,但我相信这不在所要求的范围内。函子采用纯函数(和函数值),而单子采用Kleisli箭头,即返回单子(和单子值)的函数。因此,您可以链接两个单子,而第二个单子可以依赖于前一个单子的结果。你不能用函子做这个。你看过吗?对Functor API的重要添加是flatMap
(或bind
或chain
或您希望如何调用它)。如果你选择了一种特定的语言,解释起来会更容易,因为纯粹的概念性答案是。正如@Bergi所说,你的问题的简单答案(在第二段中)是bind/flatMap/chain/which(一元函数)。当然,假设你的函子/单子遵守单子定律。但我不认为这是一个非常有用的概念性答案。的确,单子是函子,因为将单子转换为函子所需的只是一个单子函数的简单应用程序,用于创建map/select/etc。如果类型构造函数没有值级别,尽管您可以创建一个公认为真空的映射
函数,但您永远无法创建单元
注入函数。如果在术语级不使用类型构造函数的类型参数,也可以使用类似的技巧。函子的这个定义很奇怪。我总是读到它是可以映射的东西,比如可选的或列表。在Haskell中,它定义了用于此目的的fmap
。你是说它是任何一个函数,把一种类型映射到另一种类型。这些定义不是不兼容吗?我遗漏了什么?哈斯凯尔对函子的定义:“类函子f,其中fmap::(A->b)->fa->fb”。如您所见,它提供了一种从FA->FB映射的方法。“映射到它上面”的概念不是函子的定义,而是它在数学范围之外的用法。好吧,我对这一切都很陌生,所以我为我的无知道歉。还有一个问题(如果可以用新手友好的方式解释的话),你说函子是“从一组值到另一组值的函数”——那么函数有什么区别?难道不是所有函数都从一组值(x
)映射到另一组值(f(x)
)吗?这可能与不同的t有关
Maybe("a").flatMap(append("b")) // Maybe("ab")