简体   繁体   English

列表理解中的 Haskell 无限递归

[英]Haskell infinite recursion in list comprehension

I am trying to define a function that accepts a point (x,y) as input, and returns an infinite list corresponding to recursively calling我试图定义一个函数,它接受一个点 (x,y) 作为输入,并返回一个对应于递归调用的无限列表

P = (u^2 − v^2 + x, 2uv + y) P = (u^2 − v^2 + x, 2uv + y)

The initial values of u and v are both 0. u 和 v 的初始值都是 0。

  • The first call would be第一个电话是

    P = (0^2 - 0^2 + 1, 2(0)(0) + 2) = (1,2) P = (0^2 - 0^2 + 1, 2(0)(0) + 2) = (1,2)

  • Then that resulting tuple (1,2) would be the next values for u and v, so then it would be那么结果元组 (1,2) 将是 u 和 v 的下一个值,因此它将是

    P = (1^2 - 2^2 + 1, 2(1)(2) + 2) = (-2,6) P = (1^2 - 2^2 + 1, 2(1)(2) + 2) = (-2,6)

and so on.等等。

I'm trying to figure out how to code this in Haskell.我想弄清楚如何在 Haskell 中对此进行编码。 This is what I have so far:这是我到目前为止:

o :: Num a =>(a,a) -> [(a,a)]
o (x,y) = [(a,b)| (a,b)<- [p(x,y)(x,y)]]   
  where p(x,y)(u,v) = ((u^2)-(v^2)+x,(2*u*v)+y)

I'm really not sure how to make this work.我真的不知道如何使这项工作。 Any help would be appreciated!任何帮助,将不胜感激!

Let's first ignore the exact question you have, and focus on getting the loop working.让我们首先忽略您的确切问题,并专注于使循环正常工作。 What you want, essentially, is to have something that takes some initial value iv (namely, (0, 0) for (u, v) ), and returns the list本质上,您想要的是具有一些初始值iv (即(0, 0) for (u, v) ),并返回列表

f iv : f (f iv) : f (f (f iv)) : f (f (f (f iv))) : ...

for some function f (constructed from your p and (x, y) ).对于某些函数f (从您的p(x, y)构建)。 Moreover, you want the result to reuse the previously computed elements of the list.此外,您希望结果重用先前计算的列表元素。 If I would write a function myself that does this, it might looke like this (but maybe with some different names):如果我自己编写一个执行此操作的函数,它可能看起来像这样(但可能有一些不同的名称):

looper :: (a -> a) -> a -> [a]
looper f iv = one_result : more_results
  where
    one_result   = f iv
    more_results = looper f one_result

But, of course, I would first look if a function with that type exists.但是,当然,我会首先查看是否存在具有该类型的函数。 It does: it's called Data.List.iterate .它确实:它被称为Data.List.iterate The only thing it does wrong is the first element of the list will be iv , but that can be easily fixed by using tail (which is fine here: as long as your iteration function terminates, iterate will always generate an infinite list).它唯一做错的是列表的第一个元素将是iv ,但这可以通过使用tail轻松修复(这里很好:只要您的迭代函数终止, iterate将始终生成一个无限列表)。


Let's now get back to your case.现在让我们回到你的案例。 We established that it'll generally look like this:我们确定它通常看起来像这样:

o :: Num a => (a, a) -> [(a, a)]
o (x, y) = tail (iterate f iv)
  where
    f (u, v) = undefined
    iv = undefined

As you indicated, the initial value of (u, v) is (0, 0) , so that's what our definition of iv will be.正如您所指出的, (u, v)的初始值是(0, 0) ,这就是我们对iv的定义。 f now has to call p with the (x, y) from o 's argument and the (u, v) for that iteration: f现在必须使用o的参数中的(x, y)和该迭代的(u, v)调用p

o :: Num a => (a, a) -> [(a, a)]
o (x, y) = tail (iterate f iv)
  where
    f (u, v) = p (x, y) (u, v)
    iv = (0, 0)
    p = undefined

It's as simple as that: the (x, y) from o 's definition is actually in scope in the where -clause.就这么简单: o定义中的(x, y)实际上在where子句中的范围内。 You could even decide to merge f and p , and end up with你甚至可以决定合并fp ,最后得到

o :: Num a => (a, a) -> [(a, a)]
o (x, y) = tail (iterate p iv)
  where
    iv = (0, 0)
    p (u, v) = (u^2 - v^2 + x, 2 * u * v + y)

Also, may I suggest that you use Data.Complex for your application?另外,我可以建议您将Data.Complex用于您的应用程序吗? This makes the constraints on a a bit stricter (you need RealFloat a , because of Num.signum ), but in my opinion, it makes your code much easier to read:这使得在限制a有点更严格的(你需要RealFloat a ,因为Num.signum ),但在我看来,它使你的代码更容易阅读:

import Data.Complex
import Data.List (iterate)

{- ... -}

o :: Num (Complex a) => Complex a -> [Complex a]
o c = tail (iterate p iv)
  where
    iv = 0  -- or "0 :+ 0", if you want to be explicit
    p z = z^2 + c

You want:你要:

  1. To construct a list [(u, v)] with the head of this list equal (0, 0)构造一个列表[(u, v)] ,这个列表的头部等于(0, 0)
  2. And then map this list with the function \\(u, v) -> (u^2 - v^2 + x, 2 * u * v + y) , appending results of this function to the list.然后使用函数\\(u, v) -> (u^2 - v^2 + x, 2 * u * v + y) map此列表,将此函数的结果附加到列表中。

We can write this function as described:我们可以像描述的那样编写这个函数:

func :: (Num t) => (t, t) -> [(t, t)]
func (x, y) = (0, 0) : map functionP (func (x, y))
    where functionP (u, v) = (u^2 - v^2 + x, 2 * u * v + y)

GHCi > take 5 $ func (1, 2)
     > [(0,0),(1,2),(-2,6),(-31,-22),(478,1366)]

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

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