我只是想写一个函数splits
,它接受列表l
并返回一个元组列表,其中包含所有可能的方法来分割l
。
所以它应该像这样工作:
splits "Hello"
[("","Hello"),("H","ello"),("He","llo"),("Hel","lo"),("Hell","o"),("Hello","")]
实施1 我写的是:
splits l = [(x,y) | i <- [0 ..length l], x <- take i l, y <- drop i l]
给出了
[('H','e'),('H','l'),('H','l'),('H','o'),('H','l'),('H','l'),('H','o'),
('e','l'),('e','l'),('e','o'),
('H','l'),('H','o'),
('e','l'),('e','o'),
('l','l'),('l','o'),
('H','o'),('e','o'),('l','o'),('l','o')]
实施2 正确的解决方案是
splits l = [(take i l, drop i l) | i <- [0 ..length l]]
问题:为什么实现1和实现2做不同的事情?实施1中发生了什么?
答案 0 :(得分:5)
关键观察是x <- list
语句在第一个版本中的作用。
让我们看一下不同的例子
[i | i <-[1..3]] => [1,2,3]
因为String = [Char]
有
[c | c <- "Word"] => "Word" or equivalently ['W','o','r','d']
所以我们可以纠正你的第一个版本一个小小的一点并获得后者
splits l = [(x,y) | i <- [0 ..length l], x <- [take i l], y <- [drop i l]]
但我仍然不得不说这是相当单一的,我眼中更好的解决方案是使用递归函数。
splits :: [a] -> [([a],[a])]
splits xx = splits' [] ([],xx)
where splits' :: [([a],[a])]-> ([a],[a]) -> [([a],[a])]
splits' acc xs@(_,[]) = reverse (xs:acc)
splits' acc (xs,y:ys) = let xs' = (xs++[y],ys)
in splits' (xs':acc) xs'
或更高阶函数
splits :: [a] -> [([a],[a])]
splits xx = zipWith splitAt [0..(length xx)] (repeat xx)