2

私は Haskell で長くて少し風変わりな関数を持っています。

(#==#) :: String -> String -> Bool
str1 #==# str2 = (sum[ 1 | index <- [0..(max (length str1) (length str2))], (str1!!index == str2!!index || str1!!index == '$')] == (max (length str1) (length str2)))

要するに、この関数は 2 つの文字列が同一かどうかをチェックし、1 つ以上の '$' があれば同一と見なします [長いバージョン: 解読の時間を節約するために、2 つの文字列、リスト内包表記内のインデックス変数が必要です0 から最長の文字列の長さまで。次に、現在のインデックスにある各文字列の要素が相互に比較されるか、ドル記号と比較されます。どちらもOKです。それらがそれらの 1 つである場合、新しいリストに 1 が追加され、この新しいリストの合計が長さと等しい場合、その単語は一致します。

ただし、これを実行しようとすると、独特のエラーが発生します。

*Practice> let totals = (sum[ 1 | index <- [1..(max (length str1) (length str2))], (str1!!index == str2!!index || str1!!index == '$')] == (max (length str1) (length str2)))
*Practice> totals
*** Exception: Prelude.(!!): index too large

私は調査を行ってきましたが、この特定のエラーに対する解決策は見つかりませんでした。誰かがそれについて何か知っているなら、私はそれを最も感謝します.

(ところで、エラーの「インデックス」は、関数で使用するインデックスと同じではありません)

4

1 に答える 1

14

このタスクに頼る!!ことは、あなたが別の言語をHaskellに靴べらしようとしていることを示唆しています。よりハスケリーな解決策を紹介させてください。私の理解では、この関数は標準の文字列等価性テストを実行しますが、最初の文字列には、$任意の1文字に一致する「ワイルドカード」である文字を含めることができます。

StringHaskellではのリストにすぎないことを思い出してくださいChar。したがって、空のリストと空でないリストの2つのリストコンストラクターでパターンマッチングを行うことができます。両方のリストの両方の可能性を一致させると、4つの可能な組み合わせが得られます。

(#==#) :: String -> String -> Bool
[]     #==# []     = ???
(x:xs) #==# []     = ???
[]     #==# (y:ys) = ???
(x:xs) #==# (y:ys) = ???

両方のリストが空かどうかを検討してください。それらは一致しますか?確かにそうだとしましょう。これは重要なベースケースの選択であることがわかりますが、今のところ、元のコードに空の文字列を入れるとが生成されるという事実にアピールしますTrue

[] #==# [] = True

真ん中の2つのケースを見てみましょう。一方のリストは空ですが、もう一方は空ではありません。

(x:xs) #==# []     = ???
[]     #==# (y:ys) = ???

不均一な長さのリストに対して何が起こるかを指定したことはありません。ただし、元のアルゴリズムのように見えるものを保持するために、最初のリストがいっぱいの場合は$それを適切と呼びます。それ以外の場合は一致しません。したがって、左側のリストの最初の要素を調べ、そうである場合は$、リストの残りの部分を調べ続けます。

('$':xs) #==# []    = xs #==# []
(x:xs)   #==# []    = False
[]       #==# (_:_) = False

興味深いケース、両方が空でないケースを見てみましょう。

(x:xs) #==# (y:ys) = ???

左側の最初の文字がである場合$、右側の文字が何であれ無視し、チェックを続けます。バインドされた文字xy等しい場合は、再度チェックを続けます。それらが等しくない場合は、で停止しFalseます。

('$':xs) #==# (_:ys) = xs #==# ys
(x:xs) #==# (y:ys)
  | x == y    = undefined {- exercise to the reader -}
  | otherwise = False

この手法では、リスト内包表記ではなく、原始再帰を使用します。これがあなたにとって異質であると思われる場合は、Haskellの方法を考えるための良い入門書としてLYAH>Recursionを確認することを強くお勧めします。

于 2013-03-14T06:43:22.480 に答える