Joh*_*ler 42 haskell combinators pointfree
我刚写了以下两个函数:
fand :: (a -> Bool) -> (a -> Bool) -> a -> Bool
fand f1 f2 x = (f1 x) && (f2 x)
f_or :: (a -> Bool) -> (a -> Bool) -> a -> Bool
f_or f1 f2 x = (f1 x) || (f2 x)
Run Code Online (Sandbox Code Playgroud)
它们可能用于组合两个布尔函数的值,例如:
import Text.ParserCombinators.Parsec
import Data.Char
nameChar = satisfy (isLetter `f_or` isDigit)
Run Code Online (Sandbox Code Playgroud)
看了这两个函数后,我意识到它们非常有用.以至于我现在怀疑它们是否包含在标准库中,或者更可能是使用现有函数有一种干净的方法来执行此操作.
这样做的"正确"方法是什么?
Don*_*art 49
一个简化,
f_and = liftM2 (&&)
f_or = liftM2 (||)
Run Code Online (Sandbox Code Playgroud)
要么
= liftA2 (&&)
= liftA2 (||)
Run Code Online (Sandbox Code Playgroud)
在((->) r)applicative functor中.
适用版本
为什么?我们有:
instance Applicative ((->) a) where
(<*>) f g x = f x (g x)
liftA2 f a b = f <$> a <*> b
(<$>) = fmap
instance Functor ((->) r) where
fmap = (.)
Run Code Online (Sandbox Code Playgroud)
所以:
\f g -> liftA2 (&&) f g
= \f g -> (&&) <$> f <*> g -- defn of liftA2
= \f g -> ((&&) . f) <*> g -- defn of <$>
= \f g x -> (((&&) . f) x) (g x) -- defn of <*> - (.) f g = \x -> f (g x)
= \f g x -> ((&&) (f x)) (g x) -- defn of (.)
= \f g x -> (f x) && (g x) -- infix (&&)
Run Code Online (Sandbox Code Playgroud)
Monad版本
或者liftM2,我们有:
instance Monad ((->) r) where
return = const
f >>= k = \ r -> k (f r) r
Run Code Online (Sandbox Code Playgroud)
所以:
\f g -> liftM2 (&&) f g
= \f g -> do { x1 <- f; x2 <- g; return ((&&) x1 x2) } -- defn of liftM2
= \f g -> f >>= \x1 -> g >>= \x2 -> return ((&&) x1 x2) -- by do notation
= \f g -> (\r -> (\x1 -> g >>= \x2 -> return ((&&) x1 x2)) (f r) r) -- defn of (>>=)
= \f g -> (\r -> (\x1 -> g >>= \x2 -> const ((&&) x1 x2)) (f r) r) -- defn of return
= \f g -> (\r -> (\x1 ->
(\r -> (\x2 -> const ((&&) x1 x2)) (g r) r)) (f r) r) -- defn of (>>=)
= \f g x -> (\r -> (\x2 -> const ((&&) (f x) x2)) (g r) r) x -- beta reduce
= \f g x -> (\x2 -> const ((&&) (f x) x2)) (g x) x -- beta reduce
= \f g x -> const ((&&) (f x) (g x)) x -- beta reduce
= \f g x -> ((&&) (f x) (g x)) -- defn of const
= \f g x -> (f x) && (g x) -- inline (&&)
Run Code Online (Sandbox Code Playgroud)
完全扯掉了TomMD,我看到了and . map并且or . map忍不住想要调整它:
fAnd fs x = all ($x) fs
fOr fs x = any ($x) fs
Run Code Online (Sandbox Code Playgroud)
我觉得这些很好看.fAnd:在列表中的所有功能True,当x适用于他们?fOr:在列表中的任何功能True,当x适用于他们?
ghci> fAnd [even, odd] 3
False
ghci> fOr [even, odd] 3
True
Run Code Online (Sandbox Code Playgroud)
不过,fOr是一个奇怪的名字选择.当然是一个很好的人,可以把那些命令式程序员抛给一个循环.=)
如果你总是想要两个函数,这是更丑陋的,但我想我会概括它:
mapAp fs x = map ($x) fs
fAnd fs = and . mapAp fs
fOr fs = or . mapAp fs
> fOr [(>2), (<0), (== 1.1)] 1.1
True
> fOr [(>2), (<0), (== 1.1)] 1.2
False
> fOr [(>2), (<0), (== 1.1)] 4
True
Run Code Online (Sandbox Code Playgroud)