1

リスト[a,b,c,d,e]と初期値がありますu(明らかにa,b,c,d,e値を表します)。と に関数を適用したいとeuますf(e,u)f(d, f(e, u))次に、関数を適用したいf(c, f(d, f(e, u)))などです。「反復」を見てきましたが、リスト内の各要素に反復を適用する方法がわかりません。

私のリスト:

a = take 101 (0 : concat [[(1%1),(2*k%1),(1%1)] | k <- [1..40]])

Haskellでこれを実装するにはどうすればよいですか?

ありがとう、サム。

4

4 に答える 4

6

あなたが欲しいfoldr :: (a -> b -> b) -> b -> [a] -> b。これは、リストデータ構造の一般的な折り畳みです。(:)これは、リスト内のすべてのコンストラクターと[]コンストラクターを、指定された2つの引数で置き換えるものと考えてください。

たとえば、[1, 2, 3]として構築されたリストの数を合計すると、andの代わりにand 、like and 、ie1 : (2 : (3 : []))を見つけることができます。したがって、として実装できます。(:)[]+01 + (2 + (3 + 0))sum :: Num a => [a] -> afoldr (+) 0

于 2013-01-24T22:29:25.023 に答える
3

あなたが説明する機能は「フォールド」と呼ばれます。この場合、右から左に適用されるため、「右フォールド」です。Prelude ではfoldr関数として実装されています。

たとえば、(++)2 つの文字列を連結する関数を取り、それを最初の要素と文字列のリストに適用するとします。

Prelude> foldr (++) "u" ["a", "b", "c", "d", "e"]
"abcdeu"
于 2013-01-24T22:26:54.153 に答える
3

よくやった、foldrあなたは自分で発見した!(嘲笑などに聞こえないことを願っています。そのような意味ではありません。ほとんどの人は折り目が不自然であり、それを理解するのに非常に一生懸命考えなければなりません!)

このような状況に対処する方法として、自分で必要な関数を作成し、その型を見つけてから、 Hoogleでその型を検索して、そのような関数が既に存在するかどうかを確認することをお勧めします。

この場合、この方法で関数を記述してみてください。私たちはそれを呼びますfoo

-- If we see an empty list the result should be u
foo u f [] = u
-- If we're given a a non-empty list we recurse down the list to get a partial 
-- result, then "add on" to it:
foo u f (x:xs) = f x (foo u f xs)

この関数を定義したら、それを にロードし、そのコマンドをghci使用してその型を見つけることができます。:t

*Main> :load "../src/scratch.hs"
[1 of 1] Compiling Main             ( ../src/scratch.hs, interpreted )
Ok, modules loaded: Main.
*Main> :t foo
foo :: t1 -> (t -> t1 -> t1) -> [t] -> t1

これで、Hoogle で type を検索t1 -> (t -> t1 -> t1) -> [t] -> t1できます。一番上の結果はfoldrで、型は(a -> b -> b) -> b -> [a] -> bと同じfooですが、変数の名前が変更され、引数の順序が反転しています。検索結果は、関数がPreludeモジュール (デフォルトで Haskell によって読み込まれるモジュール) 内にあることも示しています。結果をクリックすると、ドキュメンテーションでその定義を見つけることができます。ドキュメントでは、次の式で説明されています。

foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)

彼らはf関数を中置演算子として使用していますが、混乱しないことを願っていますが、念のためこれを次のように書き換えることができます。

foldr f z [x1, x2, ..., xn] == f x1 (f x2 ... (f xn z) ...)

これはまさにあなたが望む動作です。


なぜ私は上からそんなに大したことをしたのfoldrですか?foldr実際には、リストを分解するための最も基本的な機能だからです。このようにタイプを見てください:

foldr :: (a -> b -> b)  -- ^ What to do with a list node
      -> b              -- ^ What to do with the empty list
      -> [a]            -- ^ A list
      -> b              -- ^ The final result of "taking the list apart."

多くのリスト関数は、次のように簡単に記述できることがわかりましたfoldr

map f = foldr step []
    where step x rest = (f x):rest

-- | Append two lists
xs (++) ys = foldr (:) ys xs

-- | Filter a list, keeping only elements that satisfy the predicate.
filter pred = foldr step []
    where step x rest | pred x    = x:rest
                      | otherwise = rest

-- | Find the first element of a list that satisfies the predicate.
find pred = foldr step Nothing
    where step x r | pred x    = Just x
                   | otherwise = r
于 2013-01-26T00:40:46.250 に答える
2

右折は良さそうです。

foo :: (a -> b -> b) -> b -> [a] -> b
foo f u xs = foldr (\x acc -> f x acc) u xs

言語を学ぶとき、「もっと簡単にできる方法はありますか?」という疑問を抱くことがよくあります。答えはほとんど常にイエスです。

于 2013-01-24T22:27:43.473 に答える