【问题标题】:Looping over a function in Haskell在 Haskell 中循环一个函数
【发布时间】:2012-05-01 16:31:18
【问题描述】:

我只是对这个感到困惑,它是一个 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 表达式,但我认为没有必要。顺便说一句,应该在具有偶数个项目的列表上进行洗牌。有什么想法吗?

【问题讨论】:

    标签: haskell loops repeat shuffle


    【解决方案1】:

    解决此问题的一种方法是利用惰性并使用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 加一即可获得所需的随机播放次数。

    【讨论】:

    • 您也可以按照@hammar 的描述,用tail $ iterate 生成列表,并使用elemIndex 查找重复的索引。
    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案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 返回一个无限列表,但我们只会使用它的有限部分,因此我们不会陷入无限循环。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-06
        • 2020-04-04
        • 2021-01-18
        • 2019-10-18
        • 1970-01-01
        • 2019-12-23
        相关资源
        最近更新 更多