如何将 all 与 monadic 函数一起使用?
How to use all with a monadic function?
我发现自己处于一种情况,我想将 all
与 monadic 函数一起使用。在我看来,这并不太漂亮:
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
是否有 Better™ 方法来做到这一点?
如果您已经在使用 do
表示法,我根本不会为 liftM
操心。就去
g xs = do cnds <- mapM f xs
return $ if and cnds
then 42
else 0
或者,如果您想要一个不 运行 所有 monad 的惰性 all
,我认为您需要自己编写它。
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
如果你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
但我认为这不会给您带来很多好处。相反,您也可以将 return
拉到 if-then-else
:
之外
g xs = do cnd <- and <$> mapM f xs
return $ if cnd then 42 else 0
甚至
g xs = do ys <- mapM f xs
return $ if and ys then 42 else 0
我认为大多数人会更愿意看到最后两个版本中的一个,尽管最后一个版本对于说英语的人来说有点奇怪 "if and foo then bar else baz"
我发现自己处于一种情况,我想将 all
与 monadic 函数一起使用。在我看来,这并不太漂亮:
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
是否有 Better™ 方法来做到这一点?
如果您已经在使用 do
表示法,我根本不会为 liftM
操心。就去
g xs = do cnds <- mapM f xs
return $ if and cnds
then 42
else 0
或者,如果您想要一个不 运行 所有 monad 的惰性 all
,我认为您需要自己编写它。
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
如果你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
但我认为这不会给您带来很多好处。相反,您也可以将 return
拉到 if-then-else
:
g xs = do cnd <- and <$> mapM f xs
return $ if cnd then 42 else 0
甚至
g xs = do ys <- mapM f xs
return $ if and ys then 42 else 0
我认为大多数人会更愿意看到最后两个版本中的一个,尽管最后一个版本对于说英语的人来说有点奇怪 "if and foo then bar else baz"