Functor和Monad有什么区别?

Grz*_*rek 13 monads functional-programming functor

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

据我所知,Functors本质上是不可变的容器,它暴露了map() API,派生出另一个仿函数.哪个添加可以将特定的仿函数称为monad?

据我所知,每个monad都是一个仿函数,但不是每个仿函数都是monad.

小智 10

让我在不进入范畴论的情况下解释我的理解:

函子和 monad 都提供了一些工具来包装输入,返回包装输出。

函子 =单位+地图(即工具)

在哪里,

unit = 接受原始输入并将其包装在一个小上下文中的东西。

map = 将函数作为输入,将其应用于包装器中的原始值并返回包装结果的工具。

示例:让我们定义一个将整数加倍的函数

// doubleMe :: Int a -> Int b
const doubleMe = a => 2 * a;
Maybe(2).map(doubleMe)  // Maybe(4)
Run Code Online (Sandbox Code Playgroud)

Monad = unit + flatMap(或绑定或链)

flatMap= 使 变平的工具,map顾名思义。通过下面的示例,您很快就会明白。

示例:假设我们有一个柯里化函数,仅当两个字符串都不为空时才附加两个字符串。

让我定义一个如下:

append :: (string a,string b) -> Maybe(string c)  
Run Code Online (Sandbox Code Playgroud)

现在让我们看看map(随附的工具Functor)的问题,

Maybe("a").map(append("b")) // Maybe(Maybe("ab"))  
Run Code Online (Sandbox Code Playgroud)

这里怎么有两个Maybe

嗯,就是map这样;它将提供的函数应用于包装的值并包装结果。

让我们把它分成几个步骤,

  1. 将映射函数应用于包装值;这里映射的函数是append("b"),包装的值是"a",结果是Maybe("ab")

  2. 包装结果,返回Maybe(Maybe("ab")).

现在我们感兴趣的值被包装了两次。这里来flatMap救援。

Maybe("a").flatMap(append("b")) // Maybe("ab")
Run Code Online (Sandbox Code Playgroud)

当然,函子和 monad 也必须遵循其他一些定律,但我相信这不在所要求的范围内。

  • 函子没有单位——它们正是支持“map”的东西。 (5认同)

小智 6

(请注意,这将是对类别理论概念的简化解释)

函子

函数是从一组值a到另一组值的函数:a -> b。对于编程语言,这可能是一个来自String -> Integer以下函数:

function fn(text: string) : integer

组成

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

hash(lowercase(text))

单音

Monad允许编写原本无法组合的函子,或通过在合成中添加额外的功能来组合函子,或同时进行两者。

  • 第一个例子是用于函子的Monad String -> (String, Integer)

  • 第二个例子是Monad,它计算一个值上调用的函数数

Monad包含一个Functor T,它负责所需的功能以及另外两个功能:

  • input -> T(input)
  • T(T(input)) -> T(input)

第一个功能允许将您的输入值转换为Monad可以组成的一组值。第二个功能允许合成。

因此,总而言之,每个Monad都不是Functor,而是使用Functor来完成其目的。

  • 函子的这个定义很奇怪。我一直读到它是可以映射的东西,例如可选或列表。在 Haskell 中,它为此定义了 `fmap`。您是说它是将一种类型映射到另一种类型的任何函数。这些定义不是不相容吗?我错过了什么? (5认同)
  • 有些语言将函子定义为其他类的可调用实例;这些函子与范畴论的函子无关。 (3认同)
  • 这个答案不太对。我最初也对此感到困惑。在计算机科学的上下文中,`Functor` 是指支持 `map` 操作(不仅仅是 map 函数)的“数据结构”。`map` 函数要求它接受 1 个参数并返回 1 个参数。当输入和输出类型相同时,它也可以称为“endofunctor”。 (2认同)