我不经常使用 Haskell,但我了解 Monad 的概念。
我对Kleisli triple感到困惑,但是类别,
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
andfmap
. This formulation fits more closely with the original definition of monads in category theory. Thefmap
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. Thejoin
operation, with typeM (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
我的问题是:
我认为由于 >>=
可以由 fmap
和 join
组成,一个单子(monad)函数
a -> m b
不是必需的,普通函数 a -> b
就可以满足操作,但是网上很多教程仍然坚持使用一元函数,因为那是克莱斯利三元组和单子(monad)定律。
那么,为了简单起见,我们不应该只使用非单子(monad)函数吗?只要它们是内函数即可?我错过了什么?
相关主题是
最佳答案
从某种意义上说,你是对的。正如每个单子(monad) m
是一个仿函数,我们可以使用fmap f
具有函数 f :: a -> b
转 m 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/