Ответ 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)