Ras*_*sWL 2 monads haskell list
我发现自己处于一种我想要使用allmonadic函数的情况.在我看来,这并不是真的太漂亮了:
f :: Monad m => a -> m Bool
g :: Monad m => [a] -> m Int
g xs = do cnd <- liftM (all (== True)) $ mapM f xs
if cnd
then return 42
else return 0
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来做到这一点?
如果您已经使用do-notation,我根本不会打扰liftM.只是去
g xs = do cnds <- mapM f xs
return $ if and cnds
then 42
else 0
Run Code Online (Sandbox Code Playgroud)
或者,如果你想要一个all不运行所有monad 的懒惰,我认为你需要自己编写它.
allM f xs = foldr (\x acc -> do b <- f x; if b then return True else acc) (return True) xs
g = fmap (\cnd -> if cnd then 42 else 0) . allM f
-- much nicer with `bool`:
allM f = foldr (\x acc -> f x >>= bool (return True) acc) (return True)
g = fmap (bool 42 0) . allM f
Run Code Online (Sandbox Code Playgroud)
如果您import Control.Applicative和Data.Bool(如果使用base >= 4.7),那么您可以将其写为
g xs = bool 0 42 <$> and <$> mapM f xs
-- Or equivalently
-- g xs = bool 0 42 . and <$> mapM f xs
-- g = fmap (bool 0 42 . and) . mapM f
Run Code Online (Sandbox Code Playgroud)
但我不认为这会让你获益匪浅.取而代之的是,你还可以扳指return外if-then-else:
g xs = do cnd <- and <$> mapM f xs
return $ if cnd then 42 else 0
Run Code Online (Sandbox Code Playgroud)
甚至
g xs = do ys <- mapM f xs
return $ if and ys then 42 else 0
Run Code Online (Sandbox Code Playgroud)
我认为最后两个版本中的一个是大多数人会更容易看到的,尽管最后一个版本对于说英语的人来说看起来有点奇怪"if and foo then bar else baz"