Haskell在列表理解中的无限递归

Cur*_*ous 1 recursion haskell list repeat infinite

我试图定义一个接受点(x,y)作为输入的函数,并返回一个对应于递归调用的无限列表

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

u和v的初始值均为0.

  • 第一个电话是

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

  • 那么结果元组(1,2)将是u和v的下一个值,那么它就是

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

等等.

我试图弄清楚如何在Haskell中编写代码.这是我到目前为止:

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)
Run Code Online (Sandbox Code Playgroud)

我真的不确定如何使这项工作.任何帮助,将不胜感激!

小智 8

让我们首先忽略你所拥有的确切问题,并专注于让循环工作.从本质上讲,你想要的是拥有一些初始值iv(即(0, 0)for (u, v))的东西,然后返回列表

f iv : f (f iv) : f (f (f iv)) : f (f (f (f iv))) : ...
Run Code Online (Sandbox Code Playgroud)

某些功能f(由你p和你构建(x, y)).此外,您希望结果重用以前计算的列表元素.如果我自己编写一个函数来执行此操作,它可能会像这样(但可能有一些不同的名称):

looper :: (a -> a) -> a -> [a]
looper f iv = one_result : more_results
  where
    one_result   = f iv
    more_results = looper f one_result
Run Code Online (Sandbox Code Playgroud)

但是,当然,我首先会查看是否存在具有该类型的函数.它确实:它被称为Data.List.iterate.唯一错误的是列表的第一个元素是iv,但是可以通过使用来轻松修复tail(这里很好:只要迭代函数终止,iterate将始终生成无限列表).


现在让我们回到你的案子.我们确定它通常看起来像这样:

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

正如您所指出的那样,初始值(u, v)是(0, 0),所以这就是我们的定义iv.f现在有调用p与(x, y)从o的说法与(u, v)该次迭代:

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
Run Code Online (Sandbox Code Playgroud)

就这么简单:(x, y)from o的定义实际上在where-clause的范围内.你甚至可以决定合并f和p,并最终用

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)
Run Code Online (Sandbox Code Playgroud)

另外,我可以建议您使用Data.Complex您的申请吗?这使得约束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
Run Code Online (Sandbox Code Playgroud)