1

我只是对这个感到困惑,这是一个 Haskell 循环之类的东西,我不知道如何编写。基本上,我已经定义了三个函数splitriffleshuffle

split :: [a] -> ([a],[a])
split xs = splitAt (length xs `div` 2) xs

riffle :: [a] -> [a] -> [a]
riffle xs [] = xs
riffle [] ys = ys
riffle (x:xs) (y:ys) = x:y:riffle xs ys

shuffle :: Int -> [a] -> [a]
shuffle 0 xs = xs
shuffle n xs = shuffle (n-1) (riffle a b)
    where (a, b) = split xs 

基本上 split 只是将一个列表分成两半, riffle 应该“交错”两个列表,例如:

riffle [1,2,3] [4,5,6] = [1,4,2,5,3,6]

而 shuffle 就是迭代列表项的拆分和 riffling 的数量。现在我需要定义一个函数repeats,它输出重新获得原始列表需要多少次随机播放。函数定义如下:

repeats :: [Int] -> Int

我只是不知道如何在随机播放中执行循环......我认为这与列表理解有关,但我什么也得不到。我还没有尝试过 lambda 表达式,但我认为没有必要。顺便说一句,应该在具有偶数个项目的列表上进行洗牌。有任何想法吗?

4

3 回答 3

12

解决此问题的一种方法是利用惰性并用于iterate生成输入的迭代随机播放的无限列表。

> iterate (uncurry riffle . split) "ABCDEF"
["ABCDEF","ADBECF","AEDCBF","ACEBDF","ABCDEF","ADBECF","AEDCBF","ACEBDF", ...]

列表的第一个元素是原始元素,所以我们用 删除它tail,然后使用takeWhile来获取与原始元素不同的元素。

> takeWhile (/= "ABCDEF") . tail $ iterate (uncurry riffle . split) "ABCDEF"
["ADBECF","AEDCBF","ACEBDF"]

现在,您只需要获取length该列表中的一个并添加一个即可获得所需的随机播放次数。

于 2012-05-01T16:46:19.527 回答
5

在许多情况下,您可以使用无限列表而不是“循环”。这是其中之一。

前奏函数“迭代”重复地将一个函数应用于一个值,所以(从记忆中)

iterate f x = [x, f x, f (f x), f (f (f x)) ....]

因此,如果您将“迭代随机播放”应用于起始列表,那么您将获得渐进式随机播放。然后使用 takeWhile 找到列表中与您的起点相等的第一个条目,然后使用“length”找出它有多长。

于 2012-05-01T16:44:53.557 回答
3

在 Haskell 中,迭代最常使用递归而不是循环来表示。

这通常通过使用告诉您如何进行迭代的内部函数来完成,然后简单地使用适当的参数调用内部函数。

也许您可以填补以下代码中的空白?

repeats xs = iter 1 (...) where
    iter n ys = if ys == xs
        then n
        else iter (...) (...)

另一种方法是利用 Haskell 的惰性并使用无限列表执行此操作,使用高阶函数iterate,它重复将函数应用于初始参数:

repeats xs = (...) $ takeWhile (...) $ iterate (shuffle 1) (...)

虽然iterate返回一个无限列表,但我们只会使用它的有限部分,因此我们不会进入无限循环。

于 2012-05-01T16:51:01.657 回答