3

リストを受け取り、それを分割するすべての異なる可能性のペアのリストを返す、split という名前の関数を作成しようとしています。

split [4,3,6] = [([],[4,3,6]),([4],[3,6]),([4,3],[6]),([4,3,6],[])]

今、私はこれを書きました

split :: [a] -> [([a],[a])]
split []     = [([],[])]
split (x:xs) = ([],(x:xs)):(zip (map (x:) (map fst split(xs))) (map snd split(xs)))

コードと Hugs の断片と、選択したインタープリターがこれを取得します

ERROR file:.\split.hs:3 - Type error in application
*** Expression     : map snd split xs
*** Term           : map
*** Type           : (e -> f) -> [e] -> [f]
*** Does not match : a -> b -> c -> d

エラーメッセージ。私は一体何を間違っているのですか?(map snd split xs) が
(a-> b -> c -> d) のタイプになるのはなぜですか?

4

2 に答える 2

10

あなたはあなたのparensを置き忘れました。試す

split (x:xs) = ([],(x:xs)):(zip (map (x:) (map fst (split xs))) (map snd (split xs)))

Haskellは、CやJavaのようなものと同じように、関数呼び出しに括弧を使用しません。これを書くとき、map fst split(xs)これはと同じです。つまり、コンパイラは、3つのパラメータを使用map fst split xsして呼び出そうとしていると見なします。したがって、次のようmapに呼び出しを括弧で囲む必要があります。splitmap fst (split xs)

あなたが効果的に書き込もうとしているのは、リスト用のシンプルなジッパーです。それを実装する最も簡単な方法は

import Data.List (inits, tails)

split xs = zip (inits xs) (tails xs)
于 2013-02-20T10:29:36.997 に答える
6

別の定義を次に示します。

splits :: [a] -> [(a, a)]
splits xs = map (flip splitAt xs) [0 .. length xs]

確かに、あまり効率的ではありませんが、少なくとも簡潔です:-)

initsand tailsfromを使用して、さらに短く、おそらくより効率的な別のバージョンData.List:

splits :: [a] -> [(a, a)]
splits xs = zip (inits xs) (tails xs)

それでは、少しお楽しみください。initsandtailsfoldrsとして書くことができます。ここでinitsAand を使用して、フォールドの代数tailsAとして知られているものを表します。

inits :: [a] -> [[a]]
inits = foldr initsA [[]]

initsA :: a -> [[a]] -> [[a]]
initsA x xss = [] : map (x:) xss

tails :: [a] -> [[a]]
tails = foldr tailsA [[]]

tailsA :: a -> [[a]] -> [[a]]
tailsA x xss = (x : head xss) : xss

これらの代数を使用して、それらをさらに組み合わせることができます。

splits :: [a] -> [([a], [a])]
splits = foldr splitsA [([], [])]

splitsA :: a -> [([a], [a])] -> [([a], [a])]
splitsA xy xyss = zip (initsA xy xss) (tailsA xy yss)
  where (xss, yss) = unzip xyss

これsplitsで、単一のfoldr!として定義されました。

于 2013-02-20T10:33:19.750 に答える