【问题标题】:Bind operator for non-monadic functions非单子函数的绑定运算符
【发布时间】:2021-06-11 09:19:57
【问题描述】:

我或多或少地围绕着单子,但我无法推断出表达方式

(>>=) id (+) 3

计算结果为 6。似乎表达式以某种方式简化为

(+) 3 3

但是怎么做? 3如何应用两次?有人可以解释幕后发生的事情吗?

【问题讨论】:

  • 关键是要意识到(+) :: a -> m a where m ~ (->) a 是一个单子。 (我们需要 Num a 来代替 (+) 的事实并没有改变这一点。)另外,对于同一个 monad,id :: m a。所以,我们可以有id >>= (+) :: m a,这是一个函数a -> a,可以应用于3

标签: haskell bind monads


【解决方案1】:

这源于>>= 是如何为((->) r) 类型定义的:

(f =<< g) x  =  f (g x) x

这样

(>>=) id (+) 3
=
(id >>= (+)) 3
=
((+) =<< id) 3
=
(+) (id 3) 3
=
3 + 3

查看类型:

> :t let (f =<< g) x = f (g x) x in (=<<)
let (f =<< g) x = f (g x) x in (=<<)
        :: (t1 -> (t2 -> t)) -> (t2 -> t1) -> (t2 -> t)

> :t (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b

类型匹配

t1 ~ a
(t2 ->) ~ m    -- this is actually ((->) t2)`
t ~ b

因此,这里的约束Monad m 表示Monad ((-&gt;) t2),它定义了=&lt;&lt;&gt;&gt;= 的定义,它们会被使用。

如果要从类型推导出定义,

(>>=) :: Monad m => m a -> (a -> m b) -> m b
m ~ ((->) r)

(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
(>>=)    f            g                r =  b
  where
  a  = f r
  rb = g a
  b  = rb r

简化后就是我们上面使用的那个。

如果你想“用文字”来理解它,

(=<<) :: (Monad m, m ~ ((->) r)) => (a -> m b) -> m a -> m b
(f =<< g) x  =  f (g x) x
  • g 是“可以计算”“a”的“一元值”,表示为r -&gt; a
  • f a 计算“可以计算”“b”的“一元值”,表示为r -&gt; b
  • 因此\x -&gt; f (g x) x 是一个单子值,“可以计算”一个“b”,给定一个“r”。

所以这些“非单子函数”实际上是单子值,恰好是函数。

因此,在您的示例中,g = idf = (+)

  • id 是“可以计算”“a”的“一元值”,a -&gt; a
  • (+) a 计算一个“单子值”,“可以计算”一个“b”,一个a -&gt; b,其中b 实际上也是一个a
  • 因此\x -&gt; (+) (id x) x 是一个“可以计算”“a”的单子值,给定一个“a”:
(>>=) id (+)
=
((+) =<< id) 
=
\x -> (+) (id x) x
=
\x -> (+)     x  x

【讨论】:

  • 不确定您是否需要到=&lt;&lt; 的中间翻译,但也许我遗漏了什么?
  • @shree.pat18 这是我记得的定义。 :) 它的类型(=&lt;&lt;) :: Monad m =&gt; (a -&gt; m b) -&gt; m a -&gt; m b 也与(&lt;$&gt;)(&lt;*&gt;) 的其他类型很好地对齐,所有ending with the m a -&gt; m b
  • 谢谢,非常详尽的答案,现在一切都说得通了。还要感谢 @shree.pat18 和 chi。我想借此机会询问类型缩写,例如(->) r 中的 r 代表什么,为什么不是 t1 或 a 。 t1、a、r 等有什么区别...我在网上找不到任何关于它的信息。
  • 你可能会觉得这很有用,虽然我也找不到权威文档:kowainik.github.io/posts/naming-conventions
  • 它们当然只是助记符。 r-&gt; 的右边通常是“结果”,在-&gt; 的左边我用它来提醒“读者”,当然整个类型是来自“环境”的“读者” " 所以它可能应该是e (但e 也经常是一个“错误”,例如Either e a)。 at 等用于更通用的类型。
【解决方案2】:

为威尔的出色回答增添色彩。

如果我们查看source,我们有这个:

instance Monad ((->) r) where
       f >>= k = \ r -> k (f r) r

如果我们稍微重新排列输入表达式,我们会得到 (id &gt;&gt;= (+)) 3。这现在类似于上面显示的形式。现在将输入拟合到上面的“模板”中,我们可以将输入重写为\ r -&gt; (+) (id r) r

这是我们为最终评估得出的相同表达式,即(+) (id 3) 3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多