【问题标题】:What is the difference between a Functor and a Monad?Functor 和 Monad 有什么区别?
【发布时间】:2017-12-28 09:27:04
【问题描述】:

这里有类似的问题,但它们与特定的编程语言相关,我正在寻找概念层面的答案。

据我了解,Functor 本质上是不可变的容器,它公开了派生另一个 functor 的 map() API。哪个加法可以将特定函子称为 monad?

据我所知,每个 monad 都是 functor,但并非每个 functor 都是 monad。

【问题讨论】:

  • 仿函数采用纯函数(和函数值),而 monad 采用 Kleisli 箭头,即返回 monad(和 monadic 值)的函数。因此,您可以链接两个 monad,而第二个 monad 可以取决于前一个 monad 的结果。你不能用函子做到这一点。
  • 你看过en.wikipedia.org/wiki/…吗? Functor API 的重要补充是flatMap(或bindchain,或者你想怎么称呼它)。如果你选择了一种特定的语言,它会更容易解释,因为纯概念答案是category theory
  • 正如@Bergi 所说,您的问题(在第二段中)的简单答案是存在绑定/平面映射/链/任何东西(单子函数)。当然,假设你的 Functor/Monad 遵守 monad 法则。但我不认为这是一个非常有帮助的conceptual 答案。而且,monad 确实是 functor,因为将 monad 转换为 functor 所需的只是简单地应用 monadic 函数来创建 map/select/etc。
  • 如果你的类型构造函数没有值级别的居民,你将永远无法创建unit 注入函数,尽管能够创建一个公认的空洞map 函数。如果在术语级别不使用类型构造函数的类型参数,则可以发挥类似的技巧。

标签: functional-programming monads functor


【解决方案1】:

让我在不涉及范畴论的情况下解释我的理解:

Functors 和 monads 都提供了一些工具来包装输入,返回一个包装好的输出。

Functor = 单位 + 地图(即工具)

在哪里,

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

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

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

// doubleMe :: Int a -> Int b
const doubleMe = a => 2 * a;
Maybe(2).map(doubleMe)  // Maybe(4)

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

flatMap = 扁平化map 的工具,顾名思义。下面的例子很快就会清楚。

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

让我定义一个如下:

append :: (string a,string b) -> Maybe(string c)  

现在让我们看看mapFunctor自带的工具)的问题,

Maybe("a").map(append("b")) // Maybe(Maybe("ab"))  

这里怎么有两个Maybes?

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

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

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

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

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

Maybe("a").flatMap(append("b")) // Maybe("ab")

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

【讨论】:

    【解决方案2】:

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

    函子

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

    function fn(text: string) : integer

    作曲

    组合是当您使用一个函数的值作为下一个函数的值的输入时:fa(fb(x))。例如:

    hash(lowercase(text))

    单子

    Monad 允许组合在其他情况下不可组合的 Functor,通过在组合中添加额外功能来组合 Functor,或两者兼而有之。

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

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

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

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

    第一个函数允许将您的输入值转换为我们的 Monad 可以组成的一组值。第二个函数允许组合。

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

    【讨论】:

    • 这个函子的定义很奇怪。我一直读到它是可以映射的东西,比如可选的或列表。在 Haskell 中,它为此目的定义了 fmap。您是说将一种类型映射到另一种类型的任何功能。这些定义不兼容吗?我错过了什么?
    • Haskell 中 Functor 的定义:“class Functor f where fmap :: (a -> b) -> f a -> f b”。如您所见,它提供了一种从 f a -> f b 映射的方法。您可以“映射它”的概念不是 Functor 的定义,而是它在数学范围之外的使用。
    • 好的,我对这一切都很陌生,所以我为无知道歉。再问一个问题(如果可以用一种对新手友好的方式来解释这个问题),你说函子是“从一组值到另一组值的函数” - 那么函数有什么区别?不是所有函数都从一组值(x)映射到另一组值(f(x))吗?大概跟不同的类型有关吧?
    • 据我了解,纯函数是函子,但我对此很陌生。如果我定义 square x = x * x 2 将始终映射到 4。函子应该是可组合的,我可以用上面的正方形组合 plus2 x = x + 2。这给我返回了一个新的函子,我可以在 (fmap plus2 square) 4 上进行 fmap
    • 这个答案不太对。我最初也对此感到困惑。在计算机科学的上下文中,Functor 指的是支持map 操作(不仅仅是映射函数)的“数据结构”。 map 函数要求它接受 1 个参数并返回 1 个参数。当输入和输出类型相同时,也可以称为endofunctor
    【解决方案3】:

    Swift Functor、Applicative、Monad

    Functor、Applicative、Monad:

    • 解决同样的问题 - 将包装的值放入上下文(类)中
    • 使用闭包[About]
    • 返回上下文(类)的新实例

    区别在于闭包的参数

    伪代码:

    class SomeClass<T> {
        var wrappedValue: T //wrappedValue: - wrapped value
        func foo<U>(function: ???) -> Functor<U> { //function: - function/closure
            //logic
        }
    }
    

    在哪里???

    function: (T) -> U == Functor
    function: SomeClass< (T) -> U > == Applicative
    function: (T) -> SomeClass<U> == Monad
    

    函子

    Functor 将 function 应用于 wrapped value

    伪代码:

    class Functor<T> {
        var value: T
        func map<U>(function: (T) -> U) -> Functor<U> {
            return Functor(value: function(value)) //<- apply a function to value
        }
    }
    

    应用或应用函子

    Applicative 将wrapped function 应用于wrapped value

    Functor 的差异是 wrapped function 而不是 function

    伪代码:

    class Applicative<T> {
        var value: T
        func apply<U>(function: Applicative< (T) -> U >) -> Applicative<U> {
            return Applicative(value: unwrappedFunction(value))
        }
    }
    

    单子

    Monad 将function(返回wrapped value)应用于wrapped value

    伪代码:

    class Monad<T> {
        var value: T
        func flatMap<U>(function: (T) -> Monad<U>) -> Monad<U> { //function which returns a wrapped value
            return function(value) //applies the function to a wrapped value
        }
    }
    

    斯威夫特:

    • Optional, Collection, Result 是 Functor 和 Monad
    • String是函子

    以可选为例

    enum CustomOptional<T> {
        case none
        case some(T)
        
        public init(_ some: T) {
            self = .some(some)
        }
        
        //CustomOptional is Functor
        func map<U>(_ transform: (T) -> U) -> CustomOptional<U> {
            switch self {
            case .some(let value):
                let transformResult: U = transform(value)
                let result: CustomOptional<U> = CustomOptional<U>(transformResult)
                return result
            case .none:
                return .none
            }
        }
        
        //CustomOptional is Applicative
        func apply<U>(transformOptional: CustomOptional<(T) -> U>) -> CustomOptional<U> {
            switch transformOptional {
            case .some(let transform):
                return self.map(transform)
            case .none:
                return .none
            }
        }
        
        //CustomOptional is Monad
        func flatMap<U>(_ transform: (T) -> CustomOptional<U>) -> CustomOptional<U> {
            switch self {
            case .some(let value):
                let transformResult: CustomOptional<U> = transform(value)
                let result: CustomOptional<U> = transformResult
                return result
            case .none:
                return .none
            }
        }
    }
    

    [Swift Optional map vs flatMap]

    【讨论】:

      猜你喜欢
      • 2012-01-17
      • 2010-09-20
      • 2012-01-29
      • 2020-01-31
      • 1970-01-01
      • 2012-09-29
      • 1970-01-01
      • 2012-11-12
      • 2011-11-05
      相关资源
      最近更新 更多