我在使用liftM时遇到了问题。对于(+),它工作得很好,madd a b = liftM2 (+) a b函数给了我预期的结果Just 5 `madd` Just 7 = Just 12,但是现在用(/)尝试它,它给了我奇怪的结果。
现在,操作Just 12 `mdiv` Just 0给了我Just Infinity,而我期待的是Nothing。
发布于 2020-01-24 17:08:33
Monad不是魔术,它们只是封装了特定的计算模式。
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c以及Maybe monad的特定版本,
liftM2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c这里没有关于数字和除以零的错误。这里我们所知道的是一元值是Just something还是Nothing。
这允许我们定义一个安全的除法函数,但它不会单独为我们做这件事。
Haskell不是一个智能的编写代码的AI代理。这只是另一种编程语言,程序员而不是计算机来编写程序。此外,为什么要由它来决定您是否希望发生运行时被零除的错误!
发布于 2020-01-24 16:59:59
如果你启动GHCi并尝试‘裸体’除法运算,你会得到Infinity
Prelude> 12 / 0
InfinityliftM2只允许您在一元上下文中执行操作。在Just 12和Just 0的情况下,该上下文是Maybe。它不会改变操作;它只是处理容器引入的可变性。
Prelude Control.Monad> liftM2 (/) (Just 12) (Just 0)
Just Infinity
Prelude Control.Monad> liftM2 (/) (Just 12) Nothing
Nothing
Prelude Control.Monad> liftM2 (/) Nothing (Just 0)
Nothing
Prelude Control.Monad> liftM2 (/) (Just 12) (Just 3)
Just 4.0
Prelude Control.Monad> liftM2 (/) Nothing Nothing
Nothing注意当其中一个或两个参数都为Nothing时,liftM2是如何处理的。如果没有恰好两个值,则不能调用带有两个参数(如/或+)的函数。liftM2通过返回Nothing来处理值少于两个的情况。
另一方面,如果恰好有两个值,它就会调用函数。当您使用Just 12和Just 0调用它时,您确实有两个值,并且/操作被调用,从而产生Infinity。
这和预期的一样。
发布于 2020-01-24 22:02:43
其他答案已经指出了为什么这种方式适用于Maybe monad。但当然,Maybe并不是唯一的monad。您希望这也适用于IO、解析器和所有其他monads:
foo :: IO Double
foo = liftM2 (/) (return 12) (return 0)foo应该返回什么?它不能是Nothing,因为它不在Maybe monad中。
您可以使用fail,在Maybe monad中,它的计算结果为Nothing,更常见的情况是计算为某种异常值,或者根据monad调用error。
当然,在12 / 0的特殊情况下,正确的答案实际上是Infinity。定义IEEE754标准的数字专家这样做是有原因的。
https://stackoverflow.com/questions/59892147
复制相似问题