22

これは本当にばかげた質問かもしれませんが..

3つの数値が降順か昇順かをチェックする2つのクイック関数を作成しました。

IE 2 3 5は、昇順の場合はtrue、降順の場合はfalseになります。

153は両方とも偽になります

これらの最初の2つを呼び出すだけで機能する3番目の関数を作成する必要があります。私はGHCiを使用しています。この3番目の関数は、上記の2番目の例のように番号が任意の順序になっていないかどうかを確認します

だからそれは

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

どうすればこれを行うことができますか?/=は私には機能しません

4

2 に答える 2

35

実際には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上記で定義された2つの関数descendingは述語です。ブール値を反転する代わりに、述語を反転できます。

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)
于 2013-01-28T07:31:34.630 に答える
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クラスに似ています。実際、aはドモルガンの法則(およびのデフォルト定義)によって関連付けられたBoolean2つのモノイド(topwith^&^およびbotwith )です。しかし、現在、演算子は1つの引数の述語だけでなく、任意のアリティにも取り組んでいます。たとえば、今は。^|^^&^^|^(<=) == ((<) ^|^ (==))

Booleanさらに、 ;の他の便利な「ベース」インスタンスがあります。たとえば、マシンワードタイプはBoolean、ビット演算の観点からインスタンスにすることができます。

于 2013-01-28T21:33:21.107 に答える