List 如何将all与一元函数一起使用?
我发现自己的处境是,我想将List 如何将all与一元函数一起使用?,list,haskell,monads,List,Haskell,Monads,我发现自己的处境是,我想将all与一元函数一起使用。在我看来,这并不是很漂亮: 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 f::Monad m=>a->m
all
与一元函数一起使用。在我看来,这并不是很漂亮:
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
f::Monad m=>a->m Bool
g::Monad m=>[a]->m Int
g xs=do cnd如果您已经在使用do
-notation,我根本不会为liftM
而烦恼。去买吧
g xs = do cnds <- mapM f xs
return $ if and cnds
then 42
else 0
如果您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
甚至
g xs = do ys <- mapM f xs
return $ if and ys then 42 else 0
gxs=doys首先,你不想使用all(=True)
但是和:-)事实上,更一般地说:布尔数上的相等比较几乎总是不必要的。如果不是针对和,您仍然可以只编写所有id
。您的实现没有正确地“短路”:当纯计算短路时,它必须首先运行所有副作用。请参阅monad循环包(及其兄弟,allM
)对于一个只有尽可能多的副作用才能知道答案的版本。当您引入控件时。Applicative
:值得注意的是,该函数似乎不需要Monad
约束–Applicative
足以满足g
的功能(使用而不是mapM
)。因此,即使f
需要Monad
,最好将g
中的运算符保持在更基本的级别上。@Monad约束的左端来自f
而不是mapM
。可能是f
的约束可以放宽到Applicative f=>a->f Bool
,但目前还不清楚。和mapM f xs
才是我真正想要的,太棒了+1用于bool
函数,但我认为bool042和mapmfxs
确实令人困惑,因为它在两个不同的函子实例上使用
。@Bergi明白了。尽管如此,使用等式推理可以很容易地在两者之间进行转换,但它确实使用了我编写的两个函子实例。老实说,我并不介意这种风格,因为它看起来就像你只是在用
替换$
。
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