这可能是一个非常愚蠢的问题,但是..
我写了两个快速函数来检查三个数字是降序还是升序。
IE 2 3 5 升序为真,降序为假。
1 5 3 对两者都是错误的
我需要创建第三个函数,只调用前两个函数即可。我正在使用 GHCi。第三个函数查看数字是否与上面的第二个示例不一样
所以它会像
let newfunction = (not)Ascending && (not)Descending
我该怎么做呢?/= 对我不起作用
这可能是一个非常愚蠢的问题,但是..
我写了两个快速函数来检查三个数字是降序还是升序。
IE 2 3 5 升序为真,降序为假。
1 5 3 对两者都是错误的
我需要创建第三个函数,只调用前两个函数即可。我正在使用 GHCi。第三个函数查看数字是否与上面的第二个示例不一样
所以它会像
let newfunction = (not)Ascending && (not)Descending
我该怎么做呢?/= 对我不起作用
实际上有一个not
布尔函数,但与往常一样,您必须正确选择类型。假设您现有的功能具有以下类型:
ascending :: (Ord a) => [a] -> Bool
ascending (x1:x2:xs) = x1 <= x2 && ascending (x2:xs)
ascending _ = True
descending :: (Ord a) => [a] -> Bool
descending (x1:x2:xs) = x1 >= x2 && descending (x2:xs)
descending _ = True
要求两者意味着列表必须相等,因为这是它们在我上面定义的意义上既升序又降序的唯一方法:
both xs = ascending xs && descending xs
要反转布尔值,有以下not
功能:
not :: Bool -> Bool
然后用这个函数表示两者都不是:
neither xs = not (ascending xs || descending xs)
当然,这与以下内容相同:
neither xs = not (ascending xs) && not (descending xs)
您可以将 applicative style 与 reader functor 一起使用,以使其看起来更令人愉悦:
import Control.Applicative
both = liftA2 (&&) ascending descending
neither = not . liftA2 (||) ascending descending
或者:
neither = liftA2 (&&) (not . ascending) (not . descending)
更多:这产生了谓词的概念:
type Predicate a = a -> Bool
谓词是一个布尔函数。上面定义的两个函数是ascending
谓词。descending
除了反转布尔值,您可以反转谓词:
notP :: Predicate a -> Predicate a
notP = (not .)
我们可以将它们放在谓词上,而不是布尔值上的合取和析取,这样可以更好地编写复合谓词:
(^&^) :: Predicate a -> Predicate a -> Predicate a
(^&^) = liftA2 (&&)
(^|^) :: Predicate a -> Predicate a -> Predicate a
(^|^) = liftA2 (||)
这让我们写得非常both
好neither
:
both = ascending ^&^ descending
neither = notP ascending ^&^ notP descending
以下定律适用于谓词,
notP a ^&^ notP b = notP (a ^|^ b)
所以我们可以neither
更好地重写:
neither = notP (ascending ^|^ descending)
ertes 的答案可以通过引入布尔代数的类型类来进一步推广:
import Control.Applicative (liftA2)
-- | A class for Boolean algebras.
class Boolean a where
top, bot :: a
notP :: a -> a
(^&^), (^|^) :: a -> a -> a
-- Default implementations for all methods
top = notP bot
bot = notP top
a ^&^ b = notP (notP a ^|^ notP b)
a ^|^ b = notP (notP a ^&^ notP b)
instance Boolean Bool where
top = True
bot = False
notP = not
(^&^) = (&&)
(^|^) = (||)
instance Boolean r => Boolean (a -> r) where
top = const top
bot = const bot
notP = (notP .)
(^&^) = liftA2 (^&^)
(^|^) = liftA2 (^|^)
{-
-- We can actually generalize this to any Applicative, but this requires
-- special compiler options:
instance (Applicative f, Boolean a) => Boolean (f a) where
top = pure top
bot = pure bot
notP = fmap notP
(^&^) = liftA2 (^&^)
(^|^) = liftA2 (^|^)
-}
这与标准Monoid
类类似Boolean
——a 实际上是两个由德摩根定律相关的幺半群(top
with^&^
和bot
with )( and^|^
的默认定义)。但是现在操作符不仅在单参数谓词上工作,而且在任意数量上工作;例如,现在我们有.^&^
^|^
(<=) == ((<) ^|^ (==))
此外,还有其他有用的“基础”实例Boolean
;例如,机器字类型可以按位操作被制成Boolean
实例。