我正在尝试编写一个名为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)?
答案 0 :(得分:10)
split (x:xs) = ([],(x:xs)):(zip (map (x:) (map fst (split xs))) (map snd (split xs)))
Haskell不像C和Java那样使用括号进行函数调用。当您编写map fst split(xs)
时,这与map fst split xs
相同,即编译器认为您尝试使用三个参数调用map
。因此,您需要像split
这样对map fst (split xs)
的调用进行父母代理。
您实际编写的内容是列表的简单zipper。实现它的最简单方法是
import Data.List (inits, tails)
split xs = zip (inits xs) (tails xs)
答案 1 :(得分:6)
这是另一种定义:
splits :: [a] -> [(a, a)]
splits xs = map (flip splitAt xs) [0 .. length xs]
不可否认,这不是很有效,但至少它简洁: - )
使用来自inits
的{{1}}和tails
的另一个版本更短,可能效率更高:
Data.List
现在让我们玩得开心吧。我们可以将splits :: [a] -> [(a, a)]
splits xs = zip (inits xs) (tails xs)
和inits
写为tails
s,我们使用foldr
和initsA
来表示所谓的代数折叠:
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
!