haskell - bind 可以由 fmap 和 join 组成,那么我们必须使用一元函数 a -> m b 吗?

标签 haskell math functional-programming monads functor

我不经常使用 Haskell,但我了解 Monad 的概念。

我对Kleisli triple感到困惑,但是类别,

fmap and join

Although Haskell defines monads in terms of the return and bind functions, it is also possible to define a monad in terms of return and two other operations, join and fmap. This formulation fits more closely with the original definition of monads in category theory. The fmap operation, with type (t → u) → M t → M u, takes a function between two types and produces a function that does the "same thing" to values in the monad. The join operation, with type M (M t) → M t, "flattens" two layers of monadic information into one.

帮助我了解 Monads 的背景原理。

The two formulations are related as follows:

fmap f m = m >>= (return . f)
join n   = n >>= id

fmap :: (a -> b) -> (m a -> m b)
unit :: a -> m a
join :: m (m a) -> m a
>>=  :: m a -> (a -> m b) -> m b

m >>= f  =  join $ fmap f m

我的问题是: 我认为由于 >>= 可以由 fmapjoin 组成,一个单子(monad)函数 a -> m b 不是必需的,普通函数 a -> b 就可以满足操作,但是网上很多教程仍然坚持使用一元函数,因为那是克莱斯利三元组和单子(monad)定律。

那么,为了简单起见,我们不应该只使用非单子(monad)函数吗?只要它们是内函数即可?我错过了什么?

相关主题是

Monad join function

Haskell Monad bind operator confusion

Difference in capability between fmap and bind?

最佳答案

从某种意义上说,你是对的。正如每个单子(monad) m是一个仿函数,我们可以使用fmap f具有函数 f :: a -> bm a进入m b ,但有一个问题。什么是 b

我喜欢想到这样一个m意思是“计划得到”,其中“计划”涉及纯计算之外的某种额外交互。如果您有“计划获取 Int”并且想要“计划获取 String”,则可以使用 fmap具有 Int -> String 中的函数,但该函数的类型告诉您获得 String来自Int不涉及进一步的交互。

情况并非总是如此:也许 Int是学生注册号,String是他们的名字,因此从一种转换为另一种的计划需要在某个表中进行外部查找。那么我没有来自 Int 的纯函数至String ,而是来自 Int 的纯函数到“计划获取String”。如果我fmap在我的“计划获取Int”中,这很好,但我最终得到“计划获取(计划获取String)”,我需要join外部和内部计划。

一般情况是我们有足够的信息来计算计划以获得更多。这就是a -> m b楷模。特别是,我们有return :: a -> m a ,它将我们拥有的信息转化为计划,无需采取进一步行动即可为我们提供准确的信息,并且我们有 (>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)它组成了两个这样的东西。我们还有(>=>)具有关联性并吸收 return左边和右边,很远;具有关联性并吸收 skip在经典的命令式编程中。

使用这种组合方法可以更方便地从较小的计划构建较大的计划,从而使“计划获取”层的数量保持一致一个。否则,您需要使用fmap建立一个n层计划。 ,然后执行正确的数字 join s 在外面(这将是该计划的一个脆弱属性)。

现在,由于Haskell是一种具有“自由变量”和“作用域”概念的语言,a

(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)

表示“总体输入信息”可以取 self 们已经拥有的事物的范围,留下

(>>=) ::       m b  -> (b -> m c) ->       m c

然后我们回到“bind”,它是一个以对程序员最友好的形式呈现组合结构的工具,类似于本地定义。

总而言之,您可以使用a -> b ,但通常您需要b “计划得到一些东西”,如果你想综合制定计划,那么选择这一点是很有帮助的。

关于haskell - bind 可以由 fmap 和 join 组成,那么我们必须使用一元函数 a -> m b 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51376391/

相关文章:

Python:在多维数组/列表上使用不带 lambda 的 map()

haskell - haskell 中定义类型的树

haskell 设置数据类型

haskell - HLint 可以自动执行建议的编辑吗?

ajax - 自动测试 AJAX Web UI 时使用延迟的替代方法

c# - 如何将平面上的 3D 点转换为 UV 坐标?

algorithm - 什么更大 : O(mn) OR O((m^2)/n)?

haskell - 如何处理不完整的 JSON/Record 类型(IE 缺少我稍后会填写的必填字段)?

haskell - 不同类型的通用功能

Java - 如何根据反抛物线计算指数级更高的分数