Haskell 单子与liftM
我在使用Haskell 单子与liftM,haskell,functional-programming,monads,Haskell,Functional Programming,Monads,我在使用liftM时遇到问题。对于(+)它工作正常,函数 maddab=liftM2(+)ab给出了预期的结果Just 5`madd`Just 7=Just 12 但是现在用(/)尝试它会给我奇怪的结果 mdiv a b=liftM2(/)a b现在操作Just 12`mdiv`Just 0给了我刚好无穷大 虽然我不期望有任何结果,但如果您启动GHCi并尝试“裸”除法操作,则会得到无穷大: Prelude> 12 / 0 Infinity liftM2只允许您在一元上下文中执行操作。在只
liftM
时遇到问题。对于(+)
它工作正常,函数
maddab=liftM2(+)ab
给出了预期的结果Just 5`madd`Just 7=Just 12
但是现在用(/)
尝试它会给我奇怪的结果
mdiv a b=liftM2(/)a b
现在操作Just 12`mdiv`Just 0
给了我刚好无穷大
虽然我不期望有任何结果,但如果您启动GHCi并尝试“裸”除法操作,则会得到无穷大:
Prelude> 12 / 0
Infinity
liftM2
只允许您在一元上下文中执行操作。在只有12个
和只有0个
的情况下,该上下文是可能
。它不会改变操作;它只处理容器引入的可变性
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
请注意liftM2
如何处理一个或两个参数均为Nothing
的情况。如果没有两个值,则无法调用具有两个参数(如/
或+
)的函数liftM2
通过返回Nothing
来处理值少于两个的情况
另一方面,如果正好有两个值,则调用函数。当您使用仅12
和仅0
调用它时,确实有两个值,并且调用/
操作,产生无限
这是意料之中的。如果启动GHCi并尝试“裸”除法操作,则会得到无穷大:
Prelude> 12 / 0
Infinity
liftM2
只允许您在一元上下文中执行操作。在只有12个
和只有0个
的情况下,该上下文是可能
。它不会改变操作;它只处理容器引入的可变性
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
请注意liftM2
如何处理一个或两个参数均为Nothing
的情况。如果没有两个值,则无法调用具有两个参数(如/
或+
)的函数liftM2
通过返回Nothing
来处理值少于两个的情况
另一方面,如果正好有两个值,则调用函数。当您使用仅12
和仅0
调用它时,确实有两个值,并且调用/
操作,产生无限
这是意料之中的。单子不是魔法,它们只是封装了某些计算模式
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
以及monad的具体版本
liftM2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
这里没有关于数字和被零除的错误。这里我们只知道一元值是只是一些
还是没有
这允许我们定义一个安全的除法函数,但它不能单独为我们所有人定义
Haskell不是一个智能代码编写AI代理。它只是另一种编程语言,程序员而不是计算机编写程序。此外,它为什么要为您决定是否希望运行时发生被零除的错误 单子不是魔法,它们只是封装了某些计算模式
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
以及monad的具体版本
liftM2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
这里没有关于数字和被零除的错误。这里我们只知道一元值是只是一些
还是没有
这允许我们定义一个安全的除法函数,但它不能单独为我们所有人定义
Haskell不是一个智能代码编写AI代理。它只是另一种编程语言,程序员而不是计算机编写程序。此外,它为什么要为您决定是否希望运行时发生被零除的错误 其他答案已经指出了为什么它对
Maybe
monad起作用。当然,可能不是唯一的单子。您希望它也适用于IO
、解析器和所有其他monad:
foo :: IO Double
foo = liftM2 (/) (return 12) (return 0)
foo
应该返回什么?它不能是Nothing
,因为它可能不在单子中
您可以使用fail
,它在中可能会计算为Nothing
,通常计算为某种异常值,或者根据monad调用error
当然,在12/0
的特殊情况下,正确的答案确实是无限
。定义IEEE754标准的数字专家这样做是有原因的。其他答案已经指出了为什么它对可能monad的工作方式。当然,可能不是唯一的单子。您希望它也适用于IO
、解析器和所有其他monad:
foo :: IO Double
foo = liftM2 (/) (return 12) (return 0)
foo
应该返回什么?它不能是Nothing
,因为它可能不在单子中
您可以使用fail
,它在中可能会计算为Nothing
,通常计算为某种异常值,或者根据monad调用error
当然,在12/0
的特殊情况下,正确的答案确实是无限
。定义IEEE 754标准的数值专家之所以这样做是有原因的。为什么你期望无
?因为没有定义除以0,最好的awnser应该是无
,一个单子只决定一个单子计算如何与一个返回相同类型的单子计算的函数组合。使用Maybe
时,一元上下文是可能失败的计算。您仍然需要定义失败对您的计算意味着什么。因此,在本例中,我应该添加类似于mdivab=if(b==0)的内容,而不是liftM2(/)a