在阅读monads时,我一直看到像“Xyz monad中的计算”这样的短语。计算“在某个monad中”是什么意思?
我认为我对monad的含义有一个公平的把握:允许计算产生通常是某种预期类型的输出,但可以替代地或另外地传达一些其他信息,例如错误状态,记录信息,状态等等。 on,并允许这样的计算被链接。
但是我不知道如何计算出一个单独的计算机。这只是引用产生monadic结果的函数吗?
示例:(搜索“计算中”)
答案 0 :(得分:11)
这只是引用产生monadic结果的函数吗?
是的,简而言之。
很长一段时间,因为Monad
允许您将值注入(通过return
),但一旦进入Monad
,它们就会被卡住。您必须使用evalWriter
或runCont
这样的功能,这些功能严格比Monad
更具体,才能让值“退出”。
更重要的是,Monad
(实际上,它的合作伙伴,Applicative
)是拥有“容器”并允许计算在其中发生的本质。这就是(>>=)
给你的东西,能够在Monad
内部进行有趣的计算。
因此,像Monad m => m a -> (a -> m b) -> m b
这样的函数可让您在Monad
内和周围进行计算。像Monad m => a -> m a
这样的函数可以注入Monad
。像m a -> a
这样的函数可以让你“逃避”Monad
,除非它们一般不存在(仅限于特定的)。因此,为了对话,我们喜欢讨论像Monad m => m a
这样的结果类型为“在monad中”的函数。
答案 1 :(得分:11)
通常,“monad中的计算”不仅意味着返回monadic结果的函数,而且意味着在do
块内使用的函数,或者作为(>>=)
的第二个参数的一部分,或其他任何与之相当的东西。区别与您在评论中所说的内容相关:
“计算”发生在func f中,在从输入monad中提取val之后,并且在结果被包装为monad之前。我不知道计算本身是如何“在”monad中的;它似乎显然“超出”了monad。
这不是糟糕的方式来考虑它 - 实际上,do
符号鼓励它,因为它是查看事物的便捷方式 - 但它确实导致一种略带误导的直觉。没有任何东西可以从monad中“提取出来”。要了解原因,请忘记(>>=)
- 这是一个支持do
表示法的复合操作。 monad的更基本定义是三个正交函数:
fmap :: (a -> b) -> (m a -> m b)
return :: a -> m a
join :: m (m a) -> m a
...其中m
是monad。
现在考虑如何使用以下方法实现(>>=)
:从类型m a
和a -> m b
的参数开始,您唯一的选择是使用fmap
来获取类型{ {1}}之后,您可以使用m (m b)
展平嵌套的“图层”以获得join
。
换句话说,没有任何东西被从“monad”中“取出” - 而是将计算视为更深进入monad,连续的步骤被折叠成monad的单层单子。
请注意,从这个角度来看,monad定律也更简单 - 基本上,他们说当应用m b
时,只要保留嵌套顺序(一种关联形式)并且join
引入的monadic图层不执行任何操作(return
的标识值)。
答案 2 :(得分:3)
通常以“类似集合”的monad为例,monad东西更易于掌握。想象一下,你计算两点的距离:
data Point = Point Double Double
distance :: Point -> Point -> Double
distance p1 p2 = undefined
现在你可能有一定的背景。例如。其中一个点可能是“非法的”,因为它超出了某些界限(例如在屏幕上)。因此,您将现有计算包装在Maybe
monad中:
distance :: Maybe Point -> Maybe Point -> Maybe Double
distance p1 p2 = undefined
您具有完全相同的计算,但附加功能可能存在“无结果”(编码为Nothing
)。
或者你有一组两个“可能”的点,并且需要它们的相互距离(例如,以后使用最短的连接)。然后列表monad就是你的“上下文”:
distance :: [Point] -> [Point] -> [Double]
distance p1 p2 = undefined
或者用户输入点数,这使得计算“不确定”(在某种意义上,你依赖于外部世界的事物,这可能会改变),那么IO
monad就是你的朋友:
distance :: IO Point -> IO Point -> IO Double
distance p1 p2 = undefined
计算总是保持不变,但碰巧发生在某个“上下文”中,这增加了一些有用的方面(失败,多值,非确定性)。您甚至可以组合这些上下文(monad变换器)。
您可以编写一个统一上述定义的定义,并适用于任何 monad:
distance :: Monad m => m Point -> m Point -> m Double
distance p1 p2 = do
Point x1 y1 <- p1
Point x2 y2 <- p2
return $ sqrt ((x1-x2)^2 + (y1-y2)^2)
这证明我们的计算实际上与实际的monad相比非常独立,这导致了“x在(-side)y monad中计算”。
答案 3 :(得分:1)
查看您提供的链接,似乎&#34;计算的常见用法是&#34;关于单一的monadic值。摘录:
温和的介绍 - 这里我们在SM monad中运行计算,但计算是monadic值:
-- run a computation in the SM monad
runSM :: S -> SM a -> (a,S)
所有关于monads - 以前的计算是指序列中的monadic值:
&gt;&gt; function是一个便捷运算符,用于绑定不需要序列中先前计算输入的monadic计算
了解monad - 这里的第一个计算可以参考例如getLine
,monadic值:
(binding)给出了在另一个计算中使用计算结果的内在想法,而不需要运行计算的概念。
作为类比,如果我说i = 4 + 2
,那么i
就是值6
,但它同样是一个计算,即计算4 + 2
。似乎链接的页面在这个意义上使用计算 - 计算作为monadic值 - 至少在某些时候,在这种情况下使用表达式&#34;&#34中的计算是有意义的;给定的monad。
答案 4 :(得分:0)
考虑IO
monad。类型IO a
的值是对大量(通常是无限)行为的描述,其中行为是IO事件序列(读取,写入等)。这样的值称为“计算”;在这种情况下,它是IO
monad中的计算。