如何否定一个功能?

时间:2013-01-28 07:05:13

标签: haskell

这可能是一个非常愚蠢的问题,但是......

我编写了两个快速函数,用于检查三个数字是按降序还是按升序排列。

IE 2 3 5对于升序是正确的而对于降序是错误的。

1 5 3对于两者都是错误的

我需要制作第三个函数,只需调用前两个函数即可。我正在使用GHCi。第三个函数查看数字是否与上面第二个例子中的任何顺序不相同

所以它会像

let newfunction = (not)Ascending && (not)Descending

虽然如何做到这一点? / =对我不起作用

2 个答案:

答案 0 :(得分:29)

布尔值实际上有一个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样式,使其看起来更令人愉悦:

import Control.Applicative

both    = liftA2 (&&) ascending descending
neither = not . liftA2 (||) ascending descending

或者:

neither = liftA2 (&&) (not . ascending) (not . descending)

更多:这会产生一个谓词概念:

type Predicate a = a -> Bool

谓词是布尔函数。上面定义的两个函数ascendingdescending是谓词。相反,反转布尔值,你可以反转谓词:

notP :: Predicate a -> Predicate a
notP = (not .)

而不是对布尔值进行连接和分离,我们可以将它们放在谓词上,这样可以更好地编写复合谓词:

(^&^) :: Predicate a -> Predicate a -> Predicate a
(^&^) = liftA2 (&&)

(^|^) :: Predicate a -> Predicate a -> Predicate a
(^|^) = liftA2 (||)

这让我们可以非常好地编写bothneither

both = ascending ^&^ descending

neither = notP ascending ^&^ notP descending

以下法律适用于谓词,

notP a ^&^ notP b = notP (a ^|^ b)

所以我们可以更好地重写neither

neither = notP (ascending ^|^ descending)

答案 1 :(得分:2)

通过引入布尔代数的类型类,可以进一步推广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实际上是两个幺半群(top ^&^bot ^|^ }与DeMorgan法律相关(^&^^|^的默认定义)。但是现在运营商不仅在单参数谓词上工作,而且在任意方面工作;例如,现在我们有(<=) == ((<) ^|^ (==))

此外,Boolean还有其他有用的“基础”实例;例如,机器字类型可以按位操作制成Boolean个实例。