Haskell中liftM Just执行结果不符预期是否为Bug?
关于Haskell中liftM行为的疑问解答
这不是Haskell的Bug,核心是对liftM的作用逻辑理解出现了偏差。
先明确liftM的本质
liftM的默认实现是:
liftM f m = m >>= return . f
它的作用是映射Monad容器内部的"成功值":尝试从Monad值m a中取出内部的a类型值,对其应用函数f得到b,再用return把b重新包回Monad结构,最终得到m b。
为何(liftM Just) Nothing返回Nothing而非Just(Nothing)?
对于Maybe这个Monad实例来说,其>>=操作的定义是:
Just x >>= f = f xNothing >>= _ = Nothing
当你调用(liftM Just) Nothing时,m是Nothing,触发了上面第二条规则,直接返回Nothing——因为Nothing里没有可供提取的a类型值,根本不会执行return . Just这一步。此时返回的Nothing类型是Maybe (Maybe a),完全符合函数签名。
同理,(liftM Just) (Left 1)返回Left 1的原因
Either e作为Monad时,>>=的定义是:
Right x >>= f = f xLeft err >>= _ = Left err
Left 1里携带的是错误值,并非Monad的"成功值",所以>>=直接返回原Left 1,不会执行Just函数。返回值类型是Either Int (Maybe a),同样符合函数签名。
如何得到Just(Nothing)?
你想要的是把整个Maybe值(不管是Just x还是Nothing)作为参数传给Just,而非映射Maybe内部的值。此时不需要用liftM,直接调用Just函数即可:
Just Nothing -- 结果为Just(Nothing) :: Maybe (Maybe a) Just (Left 1) -- 结果为Just(Left 1) :: Maybe (Either Int a)
如果需要一个通用函数,能把任意Monad值m a包裹成Maybe (m a),直接用Just本身就可以,它的类型签名是b -> Maybe b,当b取m a时,正好满足需求。
内容的提问来源于stack exchange,提问作者qwq_890
相关产品推荐
相关产品推荐

