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