Functional programming 函子和单子有什么区别?

Functional programming 函子和单子有什么区别?,functional-programming,monads,functor,Functional Programming,Monads,Functor,这里也有类似的问题,但它们都附加到一种特定的编程语言中,我正在寻找概念层面的答案 据我所知,函子本质上是不可变的容器,它公开了派生另一个函子的map()API。哪一个加法使得可以将特定的函子称为单子 据我所知,每个单体都是函子,但并非每个函子都是单体。(请注意,这将是对范畴论概念的简化解释) 函子 函子是从一组值A到另一组值的函数:A->b。对于编程语言,这可能是一个从String->Integer开始的函数: 函数fn(文本:字符串):整数 作文 组合是将一个函数的值用作下一个函数的值的输入:

这里也有类似的问题,但它们都附加到一种特定的编程语言中,我正在寻找概念层面的答案

据我所知,函子本质上是不可变的容器,它公开了派生另一个函子的map()API。哪一个加法使得可以将特定的函子称为单子

据我所知,每个单体都是函子,但并非每个函子都是单体。

(请注意,这将是对范畴论概念的简化解释)

函子 函子是从一组值A到另一组值的函数:
A->b
。对于编程语言,这可能是一个从
String->Integer
开始的函数:

函数fn(文本:字符串):整数

作文 组合是将一个函数的值用作下一个函数的值的输入:
fa(fb(x))
。例如:

hash(小写(文本))

单子 单子允许组合不可组合的函子,或通过在组合中添加额外功能来组合函子,或两者兼而有之

  • 第一个例子是函子
    String->(String,Integer)

  • 第二种方法的一个例子是对一个值调用的函数数进行计数的Monad

Monad包括一个函子
T
,它负责您想要的功能以及两个其他功能:

  • input->T(输入)
  • T(T(输入))->T(输入)
第一个函数允许将您的输入值转换为我们的Monad可以组合的一组值。第二个函数允许合成


总之,每个单子都不是一个函子,而是用一个函子来完成它的目的。

让我解释一下我的理解,不必进入范畴理论:

函子和单子都为包装输入提供了一些工具,返回包装输出

函子=单位+映射(即工具)

在哪里,

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")