Подтвердить что ты не робот

Как отменить функцию?

Это может быть очень глупый вопрос, но..

Я написал две быстрые функции, которые проверяют, находятся ли три числа в нисходящем или восходящем порядке.

IE 2 3 5 будет истинным для восходящего и ложного для нисходящего.

1 5 3 будет ложным для обоих

Мне нужно сделать третью функцию, которая будет работать только при вызове этих первых двух. Я использую GHCi. Эта третья функция видит, если числа не находятся в каком-либо порядке, как второй пример выше

Итак, это было бы как

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

Как мне это сделать? /= Не работает для меня

4b9b3361

Ответ 1

На самом деле существует функция 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)

Вы можете использовать аппликативный стиль с функтором считывателя, чтобы сделать этот взгляд более приятным:

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)

Ответ 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 class-a Boolean на самом деле является двумя моноидами (top с ^&^ и bot с ^|^), связанным с законами DeMorgan (определения по умолчанию для ^&^ и ^|^). Но теперь операторы работают не только на предикатах с одним аргументом, но и на произвольной сущности; например, теперь мы имеем (<=) == ((<) ^|^ (==)).

Кроме того, существуют другие полезные "базовые" экземпляры Boolean; например, типы машинных слов могут быть превращены в экземпляры Boolean с точки зрения поразрядных операций.