Haskell foldr在无限列表上,使用head

Haskell foldr在无限列表上,使用head,haskell,infinite,fold,Haskell,Infinite,Fold,我正在努力了解如何做到这一点 f :: Int -> [[Int]] -> [[Int]] f n acc = ([length $ head acc] ++ (take n $ repeat n)) : acc 给予 我可以转换到这里,然后陷入困境 [[2],[3,1]] 从f 0$f 1$foldr f undefined[2..]继续一次迭代,然后简单地内联f的定义: foldr f undefined [0..] foldr f undefined ([0:[1..])

我正在努力了解如何做到这一点

f :: Int -> [[Int]] -> [[Int]]
f n acc = ([length $ head acc] ++ (take n $ repeat n)) : acc
给予

我可以转换到这里,然后陷入困境

[[2],[3,1]]

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

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 $
现在,由于我们只需要前两个元素(
take 2
),我们得到了

[[2],[3,1]]
f 0$f 1$foldr f undefined[2..]
继续一次迭代,然后只需内联
f
的定义:

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 $
现在,由于我们只需要前两个元素(
take 2
),我们得到了

[[2],[3,1]]
如果只展开
foldr
调用,您将永远看不到任何有趣的内容。一旦对
f
的调用是表达式的开头,请展开
f
。该扩展将需要来自其
acc
的一些信息,这是后续的
foldr
调用,但它不需要全部信息,因此您将能够取得进展

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

这里我重复了两次未定义的foldr f[1..],因为使用了两次
acc
,但当然,您只需要在两个地方使用相同的结果将其展开一次。

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

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

在这里,我重复了两次未定义[1..],因为
acc
使用了两次,但是当然,您只需要在两个位置使用相同的结果来展开它一次。

如果有一个点击工具来帮助展开,那就太好了。扩展纯粹是机械的,但可能有点令人生畏。谢谢大家。如果有一个点击工具来帮助扩展,那就太好了。扩展纯粹是机械的,但可能有点令人生畏。谢谢大家。