どうですか
insertSpecial :: Eq a => a -> a -> [a] -> [a]
insertSpecial x y [] = []
insertSpecial x y (a:as) | a == x = y:a:as
insertSpecial x y (a:as) = a : insertSpecial x y as
このアプローチでは、再帰と呼ばれる一般的な方法を使用します。これは、目前のタスクが1つまたは複数の基本ケースに分割され、その結果を簡単に定義できることと、作業をパーツに分割することで解決できる一般的なケースに分割されることを意味します。一般的なケースでは、関数は小さなタスクで再帰的に呼び出されます。目標は、最終的にベースケースになり、その時点で作業が完了することです。Learn youaHaskellのこの部分も参照してください。
insertSpecial
2つの基本ケースを定義できます。
リストが空の場合、探している要素は含まれていません。この場合、リストは変更しないままにしておきたいので、単に空のリストを返します。終わったね。
リストが空ではなく、最初の要素が探している要素である場合はy
、このリストの前に貼り付けて返します。繰り返します。これで完了です。
そのため、リストは空ではありませんが、最初の要素が探している要素ではない場合があります。この場合、作業(リスト)を最初の要素と残りの要素の2つの部分に分割します。insertSpecial
リストの残りの部分を呼び出すことによって返されるリストの前に最初の要素を配置します。ここで再帰が発生しますinsertSpecial
。呼び出し自体が呼び出されます。
これについて理解するのが少し難しいかもしれないことの1つは、最後のケースが、適切な場所に要素を挿入することによって、元のリストとのみ異なるリストを生成する方法です。例を考えてみましょう。リストがあるとしましょう
['h','e','l','o']
Haskellでは、通常の文字列は単なる文字のリストであることに注意してください['h','e','l','o'] == "helo"
。['h','e','l','o']
また、これは実際にはの構文糖衣であることに注意してください'h':'e':'l':'o':[]
。(:
要素とリストを取得し、その要素をリストの前に追加します。これはconsとも呼ばれます)。
次に、不足しているものを:'l'
の前に挿入しましょう。'o'
insertSpecial 'o' 'l' "helo"
"helo"
空ではないので、'h'
にバインドされa
、"elo"
にバインドされますas
(さらに、'o'
にバインドされx
、'l'
にバインドされ'y'
ます)。a == 'h' /= 'o' == x
3番目のケースなので、
insertSpecial 'o' 'l' ('h':"elo") = 'h' : insertSpecial 'o' 'l' "elo"
ここでinsertSpecial 'o' 'l' "elo"
、再び3番目のケースに分類されます("elo"
空ではなく'o' /= 'e'
):
insertSpecial 'o' 'l' ('e':"lo") = 'e' : insertSpecial 'o' 'l' "lo"
これも3番目のケースにつながります。
insertSpecial 'o' 'l' ('l':"o") = 'l' : insertSpecial 'o' 'l' "o"
さて、最後の呼び出しで、実際ににバインド'o'
しa
ているのはに等しくx
、2番目のケースでは、()の値を(y
)'l'
と(a
)の前に追加するので、次のようになります。'o'
as
[]
insertSpecial 'o' 'l' ('o':[]) | 'o' == 'o' = 'l' : 'o' : []
これらすべての置換をまとめると、次のようになります。
insertSpecial 'o' 'l' "helo" =
'h' : insertSpecial 'o' 'l' "elo" =
'h' : 'e' : insertSpecial 'o' 'l' "lo" =
'h' : 'e' : 'l' : insertSpecial 'o' 'l' "o" =
'h' : 'e' : 'l' : 'l' : 'o' : []
そして、上記のように'h' : 'e' : 'l' : 'l' : 'o' : [] == ['h','e','l','l','o'] == "hello"
。わーい。