问题是:定义一个需要a的函数shuffle :: Int -> [a] -> [a]
自然数n和偶数长度列表,然后拆分然后将列表重复n次。例如,shuffle 2 [1,2,3,4,5,6] = [1,5,4,3,2,6]
。我有一个相应的功能浅滩,但我不知道如何拆分列表。
我的浅滩功能是:
riffle :: [a] -> [a] -> [a]
riffle [] ys = ys
riffle xs [] = xs
riffle (x:xs)(y:ys) = x : y : riffle xs ys
我开始洗牌,我想,这就是我所拥有的:
shuffle :: Int -> [a] -> [a]
shuffle [] = []
shuffle a xs = (length xs) 'div' a
我试图将一个清单划分为指定的部分" a"。我是Haskell的新手,我仍然不确定这一切是如何运作的:所有的帮助都表示赞赏。
答案 0 :(得分:5)
要将列表分成两半,按顺序将两半分开,你通常应该使用乌龟和野兔算法。
-- split2 xs = splitAt (length xs `quot` 2) xs
split2 :: [a] -> ([a], [a])
split2 xs0 = go xs0 xs0
where
go (_:_:hs) (t:ts) =
let (front, rear) = go hs ts
in (t:front, rear)
go _ ts = ([], ts)
这通常比计算列表的长度并除以2更有效。即使列表是无限的,它也会起作用。
但是,在这种情况下,你不需要懒惰的版本;你马上要立即使用下半场。因此,如果您愿意,可以使用更多Lisp / Scheme / ML风格的版本:
split2' :: [a] -> ([a], [a])
split2' xs0 = go [] xs0 xs0
where
go front (_:_:hs) (t:ts) = go (t:front) hs ts
go front _ ts = (reverse front, ts)
我不确定哪个会更快,但split2'
不太容易受到编译器转换引入的空间泄漏的影响。
答案 1 :(得分:1)
不是一个好的洗牌,你的第一个和最后一个元素永远不会移动。
这样的事情?
> let shuffle 0 x = x
shuffle n x = shuffle (n-1) $ uncurry riffle $ splitAt (length x `div` 2) x
或使用iterate