有什么办法 "lift" 构造函数吗?
Is there any way to "lift" a constructor?
假设我有一个函数(下例中的 plusOne
)只接受 returns 一个 Int
。但是我没有 Int
;相反,我有一个 Maybe Int
;如果这个 Maybe Int
包含一个值,那么我想将它传递给 plusOne
并获得任何 plusOne
returns 的 Just
,或者如果它是 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 Int
获得一个 Maybe (SomeData 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
上面的两种解决方案(使用 >>=
或使用 liftM
)都需要通过匿名 lambda 函数,根据我的直觉,这不是必需的,只会破坏代码。有办法避免吗?我能否以某种方式 "lift" someData
构造函数,就像我可以在第一个片段中提升 plusOne
一样?
你可以简单地使用函数组合:
main =
let n = Just 15
res = n >>= Just . SomeData
in print res
尽管正如 Robin Zigmond 指出的那样,您可以简单地使用 fmap
,因为 fmap f x
等同于 x >>= return . f
,而 return == Just
相当于 Maybe
单子。
main = let n = Just 15
res = fmap SomeData n -- or SomeData <$> n
in print res
故事的寓意:不要在只需要仿函数的地方使用 monad。
假设我有一个函数(下例中的 plusOne
)只接受 returns 一个 Int
。但是我没有 Int
;相反,我有一个 Maybe Int
;如果这个 Maybe Int
包含一个值,那么我想将它传递给 plusOne
并获得任何 plusOne
returns 的 Just
,或者如果它是 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 Int
获得一个 Maybe (SomeData 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
上面的两种解决方案(使用 >>=
或使用 liftM
)都需要通过匿名 lambda 函数,根据我的直觉,这不是必需的,只会破坏代码。有办法避免吗?我能否以某种方式 "lift" someData
构造函数,就像我可以在第一个片段中提升 plusOne
一样?
你可以简单地使用函数组合:
main =
let n = Just 15
res = n >>= Just . SomeData
in print res
尽管正如 Robin Zigmond 指出的那样,您可以简单地使用 fmap
,因为 fmap f x
等同于 x >>= return . f
,而 return == Just
相当于 Maybe
单子。
main = let n = Just 15
res = fmap SomeData n -- or SomeData <$> n
in print res
故事的寓意:不要在只需要仿函数的地方使用 monad。