如何在Haskell中定义对函数的递归调用列表

时间:2019-07-24 14:53:35

标签: list haskell recursion iteration higher-order-functions

我想做的就是定义一个这样的函数:

[f 0, f f 0, f f f 0, f f f f 0, f f f f f 0..]

或者换句话说,每个元素是通过函数运行的最后一个元素。

我尝试过几次以与我在Haskell中看到斐波那契数列的方式相似的方式来工作,方法是调用带有预定义的前几个元素的列表:

fib = 0 : 1 : zipWith (+) fib (tail fib)

ls = 0 : f 0 : f (last ls)

如果我将f定义为一个简单的addOne函数,例如:

f =(+1)

我收到此错误:

<interactive>:124:5: error:
* Occurs check: cannot construct the infinite type: a ~ [a]
  Expected type: [[a]]
    Actual type: [a]
* In the expression: 0 : (f 0) : f (last y)
  In an equation for `y': y = 0 : (f 0) : f (last y)
* Relevant bindings include
    y :: [[a]] (bound at <interactive>:124:1)

我如何创建一个具有这种功能的列表?

4 个答案:

答案 0 :(得分:6)

我喜欢你的尝试

ls = 0 : f 0 : f (last ls)

这些是它的问题:

  • 没有类型签名。始终编​​写类型签名。从技术上讲,它们是可选的,但是男孩会帮助您了解正在发生的事情以及您甚至想要什么。
  • 您正在尝试将f直接应用于列表,但应该在 list元素上运行。 (这是导致您出现错误消息的原因。)
  • 无限列表上的
  • last可能不好。无论如何,这都不是您想要的:f应该应用于尾部的 all 个元素。这就是map的目的。

因此,以下是该尝试的正确且完整的实现:

iterate' :: (a -> a) -> a -> [a]
 -- altn.:  (Int->Int) -> [Int], without x₀ but always starting from 0
iterate' f x₀ = ls
 where ls = x₀ : f x₀ : map f (tail ls)

这实际上并没有给出[f 0, f (f 0), f (f (f 0)) ..],而是从0开始。要从f 0开始,只需删除独立的x₀

iterate' f x₀ = ls
 where ls = f x₀ : map f (tail ls)

...但是它不会终止(感谢@WillNess),因为tail现在将永远递归。 但是您实际上并不需要tail !这是正确的定义:

iterate' f x₀ = ls
 where ls = f x₀ : map f ls

答案 1 :(得分:5)

如果您想自己定义它,而不是使用@WillemVanOnsem指出的迭代,那么简单的原始递归就是您的朋友:

f :: (a -> a) -> a -> [a]
f g x = let new = g x in new `seq` new : f g new

这类似于迭代,只是迭代从您提供的元素(第一个x)开始,而不是该函数的第一个应用程序:

iterate :: (a -> a) -> a -> [a]
iterate f x =  x : iterate f (f x)

hoogling可以获取此类功能的自我教育,并读取基本软件包中找到的任何搜索命中的implementation

答案 2 :(得分:4)

Haskell已经具有该功能:iterate :: (a -> a) -> a -> [a]。例如:

Prelude> take 10 (iterate (2*) 1)
[1,2,4,8,16,32,64,128,256,512]

您的问题稍有不同,因为第一个元素应该是f 0,而不是0,但是我们可以简单地将f应用于它,或者在{结果。例如:

tail :: [a] -> [a]

例如:

ls :: Num a => (a -> a) -> [a]
ls = tail . flip iterate 0

答案 3 :(得分:4)

或者自己动手:

for(CompletableFuture<Object> future : lists){
  future.whenComplete((obj, err) -> performOtherOperation(obj));
}

输出:

fn f a = (f a) : (fn f (f a))

main = print $ take 6 $ fn (5+) 1