7

次のことを考慮してください

data Predicate = Pred Name Arity Arguments

type Name      = String
type Arity     = Int
type Arguments = [Entity]
type Entity    = String

これにより、

Pred "divides" 2 ["1", "2"]
Pred "between" 3 ["2", "1", "3"]

だけでなく、「違法」

Pred "divides" 2 ["1"]
Pred "between" 3 ["2", "3"]

アリティが引数リストの長さと一致しないため、「不正」です。

このような関数を使用しないと

makePred :: Name -> Arity -> Arguments -> Maybe Predicate
makePred n a args | a == length args = Just (Pred n a args)
                  | otherwise = Nothing

Predicate モジュールから makePred のみをエクスポートする場合、値コンストラクターの正確性を強制する方法はありますか?

4

2 に答える 2

6

簡単な答えは、スマート コンストラクターからアリティを削除することです。

makePred :: Name -> Arguments -> Predicate
makePred name args = Pred name (length args) args

Pred次に、モジュールからコンストラクターを公開せず、クライアントに強制的makePredMaybe.

その不変条件を強制する直接的な方法はありません。つまり、型チェックを行うことはできませんが、行うことはできませmakePred 2 ["a","b"]makePred 2 ["a","b","c"]。そのためには、実際の依存型が必要です。

高度な機能 ( s + ファントム型) を使用して不変条件を強制するように haskell を説得する途中の場所がありますが、GADTソリューション全体を書き出した後、私はあなたの質問に実際には対処していないことに気付きました。そのような手法は実際には適用されません。特にこの問題に。彼らは通常、一般的に価値があるよりも多くの問題を抱えています. 私はスマートコンストラクターに固執します。

スマート コンストラクターのアイデアの詳細な説明を書きました。これは、型検証と実行時検証の間の非常に快適な中間点であることが判明しました。

于 2011-01-27T08:21:29.123 に答える
0

上記の制限を適用可能にする場合はPredicate、クラスを作成する必要があり、各種類の述語は、のインスタンスである独自のデータ型であるように思われますPredicate

これにより、述語に文字列型以外の引数が含まれる可能性があります。

このようなもの(未テスト)

data Entity = Str String | Numeric Int

class Predicate a where
    name :: a -> String
    arity :: a -> Int
    args :: a -> [Entity]
    satisfied :: a -> Bool

data Divides = Divides Int Int
instance Predicate Divides where
    name p = "divides"
    arity p = 2
    args (Divides n x) = [(Numeric n), (Numeric x)]
    satisfied (Divides n x) = x `mod` n == 0

これで問題が解決する場合と解決しない場合がありますが、検討することは確かに強力なオプションです。

于 2011-01-26T23:44:02.983 に答える