7

特定のブール式の真理値表を生成しようとしています。新しい Datatype BoolExpr を作成することでこれを行うことができますが、無名関数で行いたいと考えています。次のように動作するはずです:

> tTable (\x y -> not (x || y))
output:
F F | T
F T | F
T F | F
T T | F

私のアプローチ:

tbl p = [(uncurry p) tuple | tuple <- allval]
        where allval=[(x,y) | x <- [False,True], y <- [False,True]]

これは機能しますが、2 つの引数に対してのみです。私は任意の数の引数に対してそれをやりたいです。そこで、リストから引数を取得する関数を作成することにしました。

argsFromList f []     = f
argsFromList f (x:xs) = argsFromList (f x) xs

これは動作しません:

 Occurs check: cannot construct the infinite type: t = t1 -> t
   Expected type: t -> [t1] -> t1 -> t
   Inferred type: (t1 -> t) -> [t1] -> t1 -> t
 In the expression: argsFromList (f x) xs

ここで何が問題なのかわかりません。誰かが私を正しい方向に向けたり、リンクを投稿したりできれば、とても感謝しています。

4

3 に答える 3

13

任意の数の引数を持つブール関数の真理値表を作成する場合は、複数の型に対して機能する必要がある関数を作成しているため、型クラスを使用する必要があります。

{-# LANGUAGE FlexibleInstances #-}

class TruthTable a where
  truthTable :: a -> [([Bool], Bool)]

instance TruthTable Bool where
  truthTable b = [([], b)]

instance TruthTable a => TruthTable (Bool -> a) where
  truthTable f = [ (True  : inps, out) | (inps, out) <- truthTable (f True)] ++ 
                 [ (False : inps, out) | (inps, out) <- truthTable (f False)]

例えば:

*Main> mapM_ print $ truthTable (&&)
([True,True],True)
([True,False],False)
([False,True],False)
([False,False],False)
于 2011-12-12T17:59:13.680 に答える
4

ここでの問題は、再帰的なステップに対して別の型で関数を再帰的に呼び出そうとしていることです。定義を考えてみましょう:

argsFromList f []     = f
argsFromList f (x:xs) = argsFromList (f x) xs

自分で型を推測してみましょう。f最初の引数は少なくとも 1 つの引数の関数でなければならず、2 番目の引数(x:xs)はリストであり、リスト要素は の最初の引数と同じ型でなければならないことがすぐにわかりますf。最初のケースでは引数fが返されるため、最終的な戻り値の型は最初の引数と同じでなければなりません。だから私たちはこれから始めます:

argsFromList :: (a -> ?) -> [a] -> (a -> ?)

未知の型を見つけるに?は、再帰呼び出しで構成される 2 番目のケースを調べます。引数xsは同じリスト型で、引数の(f x)型は?です。これは type を持つ再帰呼び出しの最初の引数として使用されているため、これはと同じ型であると(a -> ?)結論付けることができます。?(a -> ?)(a -> (a -> ?))(a -> (a -> (a -> ?)))

それはもちろん「無限型」だろう。

単一の型の可変数の引数を使用する関数でこれを行いたい場合は、個々の引数ではなく、値のリストを取る関数を使用することをお勧めします。それ以外の場合は、各バージョンを個別に作成するか、高度な言語機能を含む難解なトリックを使用する必要がありますが、どちらもこのような単純なケースでは魅力的ではありません.

于 2011-12-12T17:26:40.503 に答える
2

あなたが求めていることは、まったく些細なことではありません。Haskell では、可変数の引数を持つ関数を適用する関数を簡単に処理できません。たとえば、 のzip 関数はData.Listzip、さまざまな数の引数 ( 、zip3zip4、...)に対して別々のバリアントで提供されます。同様にControl.MonadliftMliftM2liftM3...

基本的に、引数の数が不明な関数に割り当てることができる最も一般的な型はa -> b; 1 桁の真理関数はBool -> Bool(a = Bool, b = Bool)、2 桁の真理関数はBool -> (Bool -> Bool)(a = Bool, b = Bool -> Bool)、3桁の真理関数は (a Bool -> (Bool -> (Bool -> Bool))= , b Bool= )Bool -> (Bool -> Bool)などです。しかし、渡された関数を見て、最初の矢印の右側にある型を知る簡単な方法はありません。

動作させることができる解決策の 1 つのタイプは、型クラスを使用して、引数関数の型ごとに真理値表メーカー関数の個別のインスタンスを定義することです。このスレッドでの Sjoerd Visscher の答えは、再帰的なインスタンス定義を使用してすべての関数サイズに対してそれを行うことです (再帰的なTruthTable a => TruthTable (Bool -> a)宣言に注意してください)。Applicative型クラスを使用して構築できる他のソリューションがあるかもしれません。

于 2011-12-12T19:43:08.683 に答える