たとえば、文字列から文字列のリストに単一の文字を追加する関数を作成しようとしています。
combine ", !" ["Hello", "", "..."] = ["Hello,", " ", "...!"]
私はこれを試しました:
combine :: String -> [String] -> [String]
combine (y:ys) (x:xs) =
[x:y, combine ys xs]
たとえば、文字列から文字列のリストに単一の文字を追加する関数を作成しようとしています。
combine ", !" ["Hello", "", "..."] = ["Hello,", " ", "...!"]
私はこれを試しました:
combine :: String -> [String] -> [String]
combine (y:ys) (x:xs) =
[x:y, combine ys xs]
簡単なものは
combine :: [Char] -> [String] -> [String]
combine [] _ = []
combine _ [] = []
combine (c:cs) (x:xs) = x ++ [c] : combine cs xs
または、さらに単純にzipWith
combine :: [Char] -> [String] -> [String]
combine = zipWith (\c x -> x ++ [c])
これを機能させるには、少し余分な作業が必要でした。私はあなたのためにそれを分解します。
まず、関数の型を として指定しました[Char] -> [String] -> [String]
。最初の引数に使用String
することもできましたが、概念的に操作しているのは、文字列と文字列のリストではなく、文字のリストと文字列のリストです。
次に、この関数のエッジ ケースを指定する必要がありました。いずれかの引数が空のリストの場合はどうなります[]
か? 簡単な答えは、その時点で計算を終了することです。
combine [] _ = []
combine _ [] = []
ここで_
は何にでも一致しますが、戻り値で使用されないため破棄します。
次に、関数の実際の本体として、最初の文字と最初の文字列を取得し、その文字を文字列の末尾に追加します。
combine (c:cs) (x:xs) = x ++ [c]
cs
しかし、これはor xs
、残りのリストでは何もしません(また、上記の型シグネチャでコンパイルすることさえできません)。続行する必要があります。リストを生成しているので、これは通常 prepend 演算子で行われます。:
combine (c:cs) (x:xs) = x ++ [c] : combine cs xs
zipWith
ただし、これは非常に一般的なパターンであるため、特殊なケースを処理するヘルパー関数が呼び出されます。その型シグネチャは
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
両方の入力リストを同時にたどり、対応する要素を提供された関数に渡します。適用したい関数は(ラムダ関数に変換された)ので、次のよう\c x -> x ++ [c]
にドロップできますzipWith
combine cs xs = zipWith (\c x -> x ++ [c]) cs xs
しかし、Haskell では、可能な場合は引数をドロップできるので、これを eta に減らすことができます。
combine :: [Char] -> [String] -> [String]
combine = zipWith (\c x -> x ++ [c])
以上です!
リストを要素ごとに結合したいとき、それは通常zip
あなたが見ている です。この場合、要素をどのように組み合わせたいかを正確に知っていzipWith
ます。
zipWith
「結合関数」を取り、その結合関数を使用して2つのリストを結合する関数を作成します。append
文字列の末尾に文字を追加するため、「結合」関数を呼び出しましょう。次のように定義できます。
append char string = string ++ [char]
これがどのように機能するかわかりましたか?例えば、
append 'e' "nic" = "nice"
また
append '!' "Hello" = "Hello!"
zipWith
これで、「結合関数」を取り、その関数を使用して 2 つのリストを結合する関数を作成することを思い出してください。したがって、関数は次のように簡単に実装されます
combine = zipWith append
次のようappend
に、指定したリストの各要素に対して順番に実行されます。
combine ", !" ["Hello", "", "..."] = ["Hello,", " ", "...!"]
あなたは近くにいます。あなたが持っているものにはいくつかの問題があります。
y は Char 型を持ち、x は [Char] のエイリアスである String 型を持ちます。つまり、y : x を使用してリストの先頭に y を追加できますが、同じ:
演算子を使用してリストの最後に y を追加することはできません。代わりに、y をリストにして、リストを結合します。
x ++ [y]
ベース ケースも存在する必要があります。そうでない場合、この再帰は、リストとクラッシュのいずれにも要素がなくなるまで続行されます。この場合、追加したいものは何もない可能性があります。
combine [] [] = []
最後に、要素を作成したら、y ++ [x]
計算した残りの項目の先頭に追加します。したがって、:
それをリストにコンスするために使用します。
combine :: String -> [String] -> [String]
combine [] [] = []
combine (x : xs) (y : ys) = (y ++ [x]) : (combine xs ys)
このコードに関する注意点として、文字列内の文字数がリスト内の文字列数と異なるポイントがある場合、これはクラッシュします。その場合、さまざまな方法で処理できます。bheklilr の回答はこれに対応しています。
kqrの答えも完璧に機能し、おそらく実際に使用するのに最適なものです.