简体   繁体   English

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

[英]How to define a list of recursive calls to a function in Haskell

What I would like to do is define a function like this: 我想要做的是定义一个这样的函数:

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

Or in other words, where each element is the last element that is run through a function. 或者换句话说,每个元素是通过函数运行的最后一个元素。

I have tried a few times to get this working with ways similar to ways I have seen the Fibonacci sequence in Haskell, by calling the list with the first few elements pre-defined: 我已经尝试过几次使用类似于我在Haskell中看到Fibonacci序列的方法,通过使用预定义的前几个元素调用列表:

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

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

If I define f as a simple addOne function like so: 如果我将f定义为一个简单的addOne函数,如下所示:

f = (+ 1) f =(+ 1)

I get this error: 我收到此错误:

<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)

How do I create a list that functions like this does? 如何创建一个像这样的功能列表?

I like your attempt 我喜欢你的尝试

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

These are the problems with it: 这些都是它的问题:

  • No type signature. 没有类型签名。 Always write type signatures. 始终写类型签名。 They are technically speaking optional, but boy do they help to understand what's going on and what you even want. 从技术上讲,它们是可选的,但是男孩帮助他们了解正在发生的事情和你甚至想要的事情。
  • You're trying to apply f directly to a list, but it's supposed to operate on list elements . 您正在尝试将f直接应用于列表,但它应该在列表元素上运行。 (That's the cause of your error message.) (这是您的错误消息的原因。)
  • last on an infinite list can be no good. last一个无限的名单可能没有好处。 Anyways this is not what you want: f should be applied to all elements of the tail instead. 无论如何这不是你想要的: f应该应用于尾部的所有元素。 That's what map is there for. 这就是map的用途。

So, a correct and complete implementation of that attempt is the following: 因此,该尝试的正确和完整实现如下:

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)

NB this doesn't actually give [f 0, f (f 0), f (f (f 0)) ..] but starts from 0 . NB这实际上并没有给出[f 0, f (f 0), f (f (f 0)) ..]但是从0开始。 To start from f 0 , simply remove the standalone x₀ : 要从f 0开始,只需删除独立的x₀

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

...which doesn't terminate however (thanks @WillNess), because the tail would now recurse forever. ...然而,这并没有终止(感谢@WillNess),因为tail现在会永远地递归。 But you don't actually need tail ! 但你实际上并不需要tail This is the proper definition: 这是正确的定义:

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

If you want to define this yourself, vs use iterate as pointed out by @WillemVanOnsem, then simple primitive recursion is your friend: 如果你想自己定义,使用@WillemVanOnsem指出的迭代,那么简单的原始递归就是你的朋友:

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

This is similar to iterate except that iterate starts with the element you provide (the first x ) instead of the first application of the function: 这与iterate类似,只是iterate以您提供的元素(第一个x )而不是函数的第一个应用程序开头:

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

A self-education can be acquired by hoogling for functions of this type and reading the implementation of any search hits found in the base package. 可以通过对这种类型的函数进行hoogling并读取基本包中找到的任何搜索命中的实现来获得自我教育

Haskell has already a function for that: iterate :: (a -> a) -> a -> [a] . Haskell已经有了一个函数: iterate :: (a -> a) -> a -> [a] For example: 例如:

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

Your question is slightly different since the first element should be f 0 , instead of 0 , but we can simply apply f to it, or use tail :: [a] -> [a] on the result. 你的问题略有不同,因为第一个元素应该是f 0而不是0 ,但我们可以简单地对它应用f ,或者对结果使用tail :: [a] -> [a] For example: 例如:

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

For example: 例如:

Prelude> take 10 (ls (1+))
[1,2,3,4,5,6,7,8,9,10]

Or roll your own: 或滚动你自己:

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

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

Output: 输出:

[6,11,16,21,26,31]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM