2011-10-24 13 views
0

私はその後、私は、[サンプル]「サンプル」と呼ばれるリストを作成(文字列と(文字列のリスト)))))のリスト内の文字列をチェックするにはどうすればよいですか?

[Test1 ("Sample1",[["works","running"]]), Test2 ("Sample2", []), 
Test1 ("Sample3", [["aborts"]] ] 

は今、私は「中止しますかどうかを確認する必要があると言う

data Sample = Test1 (String,[[String]]) 
      | Test2 (String,[[String]]) 

として定義され、「サンプル」と呼ばれるデータを持っています"Sample3"の下に存在します。私はそれを行う方法の基本的な アイデアを持っていますが、私はHaskellでそれを実装する方法がわかりません。

私の考えは、私はでそれを呼び出すことができます

check:: String -> [String] -> [Sample] -> Bool 
check samplename result samples = 

です:

check "Sample3" ["aborts"] Samples 

しかし、私はこの機能を実装するのですか。


私はこのように解決しましたが、より良いバージョンを探しています。

私のバージョンは次のとおりです。これは、トリックを行う必要があります

check:: String -> [String] -> [Sample] -> Bool 
check samplename result samples = 
    if("True" `elem` final) 
    then True 
    else False 
    where 
     final = [x | sample <- samples, 
        x <- [ case sample of 
           Test1 (name,res) = 
           if name == samplename && (result `elem` res) 
           then "True" 
           else "False" 
           Test2 (name, res) = "False"]] 
+0

'[String]'引数( "result")がどのように使われているのか分かりません。 – MatrixFrog

+0

resultは、文字列「abort」を含むリストです。 – veda

+3

コード・スタイル・ノート上。 'xならばTrue else else'は' x'と同じです。文字列 '' True ''と' 'False''を使うのは良い考えではありません。この場合、それらを完全にドロップし、単に 'True'と' False'を使用することができます。 'elem True xs'は' or xs'と同じです。 – HaskellElephant

答えて

2

ここは私のソリューションのバージョンです。しかし、私はあなたのデータが実際の問題を表しているとは思っていません。基本的にキー値のペアのリストである[Sample]のようなものを保存したい場合は、Mapを簡単に使用できます。私のソリューションの背後にある考え方はMapからも影響を受けています。私はlookup'関数を書いています。これは、キーを指定すると値を返すルックアップに似ています。残りの関数を記述するのは簡単です。あなたのアプローチに似ていますが、あまり乱雑です。

data Sample = Test1 (String,[[String]]) 
      | Test2 (String,[[String]]) 
     deriving Show 
samples = [ Test1 ("Sample1",[["works","running"]]), Test2 ("Sample2", []), Test1 ("Sample3", [["aborts"]]) ] 

fromSample :: Sample -> (String,[[String]]) 
fromSample (Test1 x) = x 
fromSample (Test2 x) = x 

lookup' :: String -> [Sample] -> Maybe [[String]] 
lookup' str [] = Nothing 
lookup' str (x:xs) | fst pair == str = Just $ snd pair 
       | otherwise = lookup' str xs 
      where pair = fromSample x 

check :: String -> [String] -> [Sample] -> Bool 
check sample str xs = case lookup' sample xs of 
         Nothing -> False 
         Just list -> str `elem` list 
2

:すべての名前が明確なことになっている場合

data Sample = Test1 String [[String]] 
      | Test2 String [[String]] 

sampleName :: Sample -> String 
sampleName (Test1 name _) = name 
sampleName (Test2 name _) = name 

getData :: Sample -> [[String]] 
getData (Test1 _ samples) = samples 
getData (Test2 _ samples) = samples 

check :: String -> [String] -> [Sample] -> Bool 
check name needle samples = any doCheck samples 
    where 
    doCheck s = if sampleName s == name 
       then needle `elem` getData s 
       else False 

を、あなたがより速く検索を中止することができます

check2 :: String -> [String] -> [Sample] -> Bool 
check2 name needle samples = go samples 
    where 
    go []  = False 
    go (s:ss) = if sampleName s == name 
       then needle `elem` getData s 
       else go ss 

テスト:

*Main> check "Sample3" ["aborts"] tst 
True 

バージョンへのコメント:

data Sample = Test1 (String,[[String]]) 
      | Test2 (String,[[String]]) 

あなたは(私のコードを参照)、ここでタプルを必要としません。一般的に

if("True" `elem` final) then True else False 

if expr then True else Falseは常にexprに置き換えることができます。なぜ文字列をブール値として使うのですか?

final = [x | sample <- samples, 
     x <- [ case sample of 
        Test1 (name,res) -> if name == samplename 
             && (result `elem` res) 
             then "True" else "False" 
        Test2 (name, res) -> "False"]] 

これはanyを使用して、リストの内包表記せずに書き換えることができます。

check:: String -> [String] -> [Sample] -> Bool 
check samplename result samples = any doCheck samples 
    where 
    doCheck (Test1 n s) = n == samplename && result `elem` s 
    doCheck _   = False 
2

我々はハイレベルで何をしなければならないかのチェックを考えるならば、我々はそれが参照するには、サンプルのすべての要素を確認する必要があります知っていますテスト "Sample3"に文字列の結果のいずれか(またはすべて、私はあなたが意味するものが不明)が含まれている場合。

だから我々は、我々が再帰を必要と知っていると我々は、機能の概要を作ることから始めることができます。

check :: String -> [String] -> [Sample] -> Bool 
check samplename result []  = False 
check samplename result (x:xs) = ... 

リストが空であるときに、何の一致が私たちはすぐにfalseを返すことができます発生しないことができます。再帰的な場合、我々はxをチェックする必要があり、一致が見つからなければxsのチェックを続ける必要があることを知っている。これを行うための1つの可能な方法は、ヘルパー関数のチェック '(チェックインだけでインライン化することもできます)です。

check samplename result (x:xs) = check' x || check samplename result xs 
    where check' ... 

大丈夫ですので、チェックは何ですか?データ型Sampleをチェックして、一致するものがあるかどうかを調べます。私たちは、サンプルが2つのコンストラクタ、Test1をを持って知っているTest2をので

check' :: Sample -> Bool 
check' (Test1 (name, values)) = ... 
check' (Test2 (name, values)) = ... 

私たちがしなければならない最初の事は、それがsamplenameと一致するかどうかを確認するために名前の値をテストしているように見えるはずです「チェック 。私たちは、簡単にチェックの子関数は、チェックで定義された変数がスコープ内にあるある「警備員のチェック以来

check' :: Sample -> Bool 
check' (Test1 (name, values)) | name == samplename = ... 
check' (Test2 (name, values)) | name == samplename = ... 
check' _           = False 

を使用してこれを行うことができますので、我々はそれらを参照することができます。名前が一致しないイベントを処理する新しいケースが追加されました。

これで、の結果のいずれか(またはすべて)の値がの値であるかどうかを確認することが考えられます。幸いなことに、プレリュードにはこれに使用できる機能があります。述語とリストのすべての要素をチェック

check :: String -> [String] -> [Sample] -> Bool 
check samplename result []  = False 
check samplename result (x:xs) = check' x || check samplename result xs 
    where check' :: Sample -> Bool 
     check' (Test1 (name, values)) | name == samplename = result `elem` values 
     check' (Test2 (name, values)) | name == samplename = result `elem` values 
     check' _           = False 

はプレリュードはのための標準的な機能を有するように一般的です:

elem :: Eq a => a -> [a] -> Bool 

機能は現在、完全な機能は、このようにある

check' :: Sample -> Bool 
check' (Test1 (name, values)) | name == samplename = result `elem` values 
check' (Test2 (name, values)) | name == samplename = result `elem` values 
check' _           = False 

なりこの。チェックを定義する1つの方法は、関数またはおよびマップを使用することです。 これは、一般的にいえあまり効率的機能をもたらすであろう。

check :: String -> [String] -> [Sample] -> Bool 
check samplename result samples = or (map check' samples) 
    where check' :: Sample -> Bool 
     check' (Test1 (name, values)) | name == samplename = result `elem` values 
     check' (Test2 (name, values)) | name == samplename = result `elem` values 
     check' _           = False 

機能は別の機能は、次に

なるよう

type ID  = Int 
type Name = String 
type Values = [[String]] 
data Sample = Test ID Name Values 

ように、データ型のための代替的な構造を適合させることにより簡略化することができます

check :: String -> [String] -> [Sample] -> Bool 
check samplename result samples = or (map check' samples) 
    where check' :: Sample -> Bool 
     check' (Test _ name values) | name == samplename = result `elem` values 
     check' _           = False 

最後に、チェック 'の結果がブールであり、ガードもブールなので、リファクタリングチェックはできません。フォールスルーケース

check :: String -> [String] -> [Sample] -> Bool 
check samplename result samples = or (map check' samples) 
    where check' :: Sample -> Bool 
     check' (Test _ name values) = name == samplename && result `elem` values 

これは**または必要(マップを.. ..)**パターンは再びプレリュード機能これを行う任意のありますように一般的です。チェックをさらに簡素化することができます

check :: String -> [String] -> [Sample] -> Bool 
check samplename result samples = any check' samples 
    where check' :: Sample -> Bool 
     check' (Test _ name values) = name == samplename && result `elem` values 
関連する問題