2011-12-12 7 views
7

私は与えられたブール式の真理値表を生成しようとしています。私は新しいデータ型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 

だから、私はリストから引数をとる関数を作ると考えました。 誰かが私を正しい方向に向けることができたり、そうしたリンクを投稿することができれば、非常に感謝しています。

+0

[なぜそのような関数定義がhaskellで許可されていないのですか?](http://stackoverflow.com/questions/6168880/why-is-such-a-function-definition-not-allowed-in- haskell) –

+0

ラムダを '(\ [x、y] - not(x || y))' 'として定義することができることに注意してください。これは自動的に、"同じ型のすべての引数" – leftaroundabout

答えて

4

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

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

はのタイプに自分自身を推測してみましょう。最初の引数fは少なくとも1つの引数の関数でなければならず、2番目の引数(x:xs)はリストであり、リストの要素は最初の引数と同じ型でなければなりません。f。最初のケースでは、引数fが返されるので、最終的な戻り値の型は最初の引数と同じでなければなりません。だから我々はこれで起動:不明なタイプ?を見つけるには

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

、我々は再帰呼び出しで構成されて第二の場合、見ることができます。引数xsは同じリストタイプで、引数(f x)はタイプ?です。再帰呼び出しの最初の引数としてタイプ(a -> ?)が使用されているので、今度は?(a -> ?)と同じタイプなので、(a -> (a -> ?))と同じタイプなので、(a -> (a -> (a -> ?)))と同じタイプであると結論できます。 。 おっとっと。

もちろん、「無限のタイプ」です。

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

+0

ありがとう!私はそれを可能にして、新しいデータ型にしましょう。 – 1nterference

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) 
2

何を求めていることは全く簡単ではありません。 Haskellは、可変数の引数を持つ関数を適用する関数を扱うのを容易にしません。たとえば、zip functions from Data.Listは、異なる数の引数(zip,zip3zip4、...)に対して別々のバリアントがあります。同様に、Control.MonadliftMliftM2liftM3

は基本的に、あなたは、引数の数が不明で機能に割り当てることができる最も一般的なタイプはa -> bで...、があります。一場所の真理関数は、(= Bool、B = BoolBool -> Boolで、二場所真理関数は、(= Bool、B = Bool -> BoolBool -> (Bool -> Bool)で、三場所Bool -> (Bool -> (Bool -> Bool))である(= Bool、B = Bool -> (Bool -> Bool)) 、 等々。しかし、最初の矢印の右側にあるタイプが何であるかを知るために渡された関数を見ることは簡単な方法ではありません。

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