在Haskell中执行`and`和`或`表示布尔函数

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)

  • 对于你,亚当,monad实例也是如此 (5认同)

Dan*_*ton 9

完全扯掉了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是一个奇怪的名字选择.当然是一个很好的人,可以把那些命令式程序员抛给一个循环.=)

  • fAnd = fmap和.序列fOr = fmap或.序列 (2认同)

Tho*_*son 7

如果你总是想要两个函数,这是更丑陋的,但我想我会概括它:

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)