【问题标题】:Haskell foldr over infinite list, using headHaskell折叠无限列表,使用head
【发布时间】:2019-01-29 16:54:22
【问题描述】:
f :: Int -> [[Int]] -> [[Int]]
f n acc = ([length $ head acc] ++ (take n $ repeat n)) : acc

我试图了解如何

take 2 $ foldr f undefined [0..]

给予

[[2],[3,1]]

我能变形到这里,然后卡住了

foldr f undefined [0..]
foldr f undefined ([0:[1..])
f 0 $ foldr f undefined [1..]
f 0 $ foldr f undefined (1: [2..])
f 0 $ f 1 $ foldr f undefined [2..]
f 0 $ f 1 $

【问题讨论】:

    标签: haskell infinite fold


    【解决方案1】:

    如果你只扩展foldr 调用,你将永远看不到任何有趣的东西。一旦对 f 的调用成为表达式的头部,请改为展开 f。该扩展将需要来自其acc 的一些信息,这是尾随的foldr 调用,但它不需要全部,因此您将能够取得进展。

    ...
    f 0 $ 
    ([length $ head (foldr f undefined [1..])] ++ (take 0 $ repeat 0)) : foldr f undefined [1..]
    ...
    

    这里我重复了两次foldr f undefined [1..],因为acc 被使用了两次,但当然你只需要扩展一次,在两个地方使用相同的结果。

    【讨论】:

      【解决方案2】:

      f 0 $ f 1 $ foldr f undefined [2..]开始,继续进行一次迭代,然后简单地内联f的定义:

      f 0 $ f 1 $ foldr f undefined [2..]
      f 0 $ f 1 $ f 2 $ foldr f undefined [3..] -- below let rest = foldr f undefined [3..]
      f 0 $ f 1 $ f 2 $ rest
      f 0 $ f 1 $ (\n acc -> ([length $ head acc] ++ (take n $ repeat n)) : acc) 2 $ rest
      f 0 $ f 1 $ (([length $ head rest] ++ (take 2 $ repeat 2)) : rest)
      f 0 $ f 1 $ (([length $ head rest] ++ [2,2]) : rest)
      f 0 $ f 1 $ ([length $ head rest,2,2] : rest)
      f 0 $ (\n acc -> ([length $ head acc] ++ (take n $ repeat n)) : acc) 1 $ ([length $ head rest,2,2] : rest)
      f 0 $ (([length $ head ([length $ head rest,2,2] : rest)] ++ (take 1 $ repeat 1)) : [length $ head rest,2,2] : rest)
      f 0 $ (([length $ [length $ head rest,2,2]] ++ [1]) : [length $ head rest,2,2] : rest) 
      -- this is the crux, we don't need to evaluate rest to evaluate the length here
      f 0 $ (([3] ++ [1]) : [length $ head rest,2,2] : rest)
      f 0 $ ([3,1] : [length $ head rest,2,2] : rest)
      ((\n acc -> ([length $ head acc] ++ (take n $ repeat n)) : acc) 0 $ ([3,1] : [length $ head rest,2,2] : rest)
      ([length $ head ([3,1] : [length $ head rest,2,2] : rest)] ++ (take 0 $ repeat 0)) : [3,1] : [length $ head rest,2,2] : rest
      ([length $ [3,1]] ++ []) : [3,1] : [length $ head rest,2,2] : rest
      [length $ [3,1]] : [3,1] : [length $ head rest,2,2] : rest
      [2] : [3,1] : [length $ head rest,2,2] : rest
      

      现在我们只需要前两个元素 (take 2),我们得到
      [[2],[3,1]]

      【讨论】:

      • 如果有一个点击工具来帮助扩展,那就太好了。扩展是纯机械的,但可能有点令人生畏。谢谢大家。
      猜你喜欢
      • 1970-01-01
      • 2020-04-30
      • 2012-02-25
      • 2011-11-15
      • 2016-05-31
      • 2018-04-13
      • 1970-01-01
      • 2018-10-11
      • 2017-09-28
      相关资源
      最近更新 更多