2

Haskellは初めてです。リストl、リストに存在する要素x、および挿入する要素yを指定して、リストlで要素xが最初に出現する前に要素y挿入する関数を作成しようとしています。要素xがリストに存在しない場合は、リストを変更しないでください。

私はこれで多くの問題を抱えています、そしてどんな提案でもありがたいです。

これは私が試したものです(「n」は要素xの最初の出現です):

insertSpecial :: Eq a => a -> a -> [a] -> [a]
insertSpecial let (ys,zs) = splitAt n xs in ys ++ [y] ++ zs
4

5 に答える 5

6

どうですか

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のこの部分も参照してください。

insertSpecial2つの基本ケースを定義できます。

  1. リストが空の場合、探している要素は含まれていません。この場合、リストは変更しないままにしておきたいので、単に空のリストを返します。終わったね。

  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' == x3番目のケースなので、

  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"。わーい。

于 2013-02-08T14:04:43.257 に答える
4

インデックスで分割する代わりに、基準を満たす最初の位置で分割することができます。

insertSpecial y x xs = front ++ [y] ++ back
  where
    (front, back) = break (== x) xs

xリストの要素である仮定が満たされない場合にエラーが必要な場合は、

insertSpecial y x xs = case break (== x) xs of
                         (front, back@(_:_)) -> front ++ [y] ++ back
                         _ -> error "Didn't find element"

しかし、直接再帰も非常に優れたソリューションです。

于 2013-02-08T14:10:10.493 に答える
1

3つのケースがあります

insertSpecial :: Eq a => a -> a -> [a] -> [a]
insertSpecial _ _ []                 = ?
insertSpecial x y (a:as) | a == x    = ?
                         | otherwise = a : rest
  where rest = ?

それぞれで何が起こりますか?

最初のケースは、リストが空であるために要素がリストにないことを確実に知っている場合です。次に、同じ空のリストを返します。

次のケースは、リストの最初の要素が探している要素である場合です。次に、yを前に付けて、同じリストを返す必要があります。

最後の再帰的なケース(otherwise)は、最初の要素が探している要素ではないが、リストの残りの部分に残っている可能性がある場合です。次に、リストの残りの部分に先頭を追加する必要がありますa。ここで、リストの残りの部分は、の最初の出現の前に先頭に追加されasます。yx

于 2013-02-08T14:06:43.867 に答える
1
insertSpecial::[Int]->Int->Int->[Int]
insertSpecial [] _ _ = []
insertSpecial list a b = concat [if x == a then [b] ++ [x] else [x] | x<-list]

aの前にbを挿入します

于 2013-02-11T00:00:53.960 に答える
1

褶曲の観点からの一般的な述語beforeEveryの発生

beforeEvery pred y  =  foldr (\ x xs -> if pred x then y : x : xs else x : xs) []

最初の出現後に終了する明示的にラップ解除された再帰関数

before :: (a -> Bool) -> a -> [a] -> [a]
before _    _ []                   = []
before pred y (x : xs) | pred x    = y : x : before pred y xs
                       | otherwise = x : before pred y xs

そのような

beforeElem x y  =  before (== x) y

また

beforeElem :: Eq a => a -> a -> [a] -> [a]
beforeElem x y  =  before (== x) y

意味

beforeElem 3 89 [1,2,3,4,5,3,4,5]  ==  [1,2,89,3,4,5,3,4,5]
于 2017-02-17T21:16:18.190 に答える