0

假设我有一个函数(plusOne在下面的示例中),它只接受并返回一个Int. 但我没有Int; 相反,我有一个Maybe Int; 如果这Maybe Int包含一个值,那么我想将它传递给plusOne并获得一个返回值,Just或者plusOne如果它是一个值,Nothing那么我希望它Nothing传播。

在这种情况下,我们必须liftM以一种优雅的方式编写代码:

import Control.Monad

plusOne :: Int -> Int
plusOne n =
    n+1 -- a very complicated computation that is failsafe

main =
    let n = Just 15 -- a very complicated computation that can fail
    in let res = liftM plusOne n
    in print res

到现在为止还挺好。但是,这样的事情也可以用构造函数来完成吗?

忘了plusOne。现在我有:data SomeData = SomeData Int并且想Maybe (SomeData Int)从我的Maybe Int. 该解决方案似乎明显不那么优雅:

import Control.Monad

data SomeData = SomeData Int
    deriving Show -- so that print works

main =
    let n = Just 15
    in let res = n >>= (\nn -> Just (SomeData nn))
    -- alternatively: in let res = liftM (\nn -> SomeData nn) n
    in print res

上述两种解决方案(with>>=或 with liftM)都需要通过一个匿名 lambda 函数,根据我的直觉,这不是必需的,只会破坏代码。有没有办法避免它?我可以以某种方式“提升”someData构造函数,就像我可以plusOne在第一个片段中提升一样吗?

4

1 回答 1

3

您可以简单地使用函数组合:

main =
    let n = Just 15
        res = n >>= Just . SomeData
    in print res

尽管正如 Robin Zigmond 指出的那样,您可以简单地使用fmap, sincefmap f x等价于x >>= return . f, andreturn == Just用于Maybe单子。

main = let n = Just 15
           res = fmap SomeData n  -- or SomeData <$> n
       in print res

故事的寓意:不要使用只需要函子的单子。

于 2019-03-20T13:16:07.980 回答