【问题标题】:Haskell infinite recursion in list comprehension列表理解中的 Haskell 无限递归
【发布时间】:2017-02-10 02:22:07
【问题描述】:

我正在尝试定义一个函数,它接受一个点 (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)

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

【问题讨论】:

  • 请不要删除您的示例代码。每个人都从某个地方开始。没有必要为此感到羞耻:)
  • @Rhymoid,你是在暗示我的小学 Logo、BASIC 和 Turbo Pascal 代码可能还有一些不足之处吗?我自己只写过完美的代码,我希望其他人也一样。编程是严肃的事情,没有任何错误的余地!

标签: list haskell recursion repeat infinite


【解决方案1】:

让我们首先忽略您的确切问题,并专注于使循环正常工作。本质上,您想要的是拥有一些初始值iv(即(0, 0) 对应(u, v)),并返回列表

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

对于某些功能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

但是,当然,如果存在具有该类型的函数,我会首先look。确实如此:它被称为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

正如您所说,(u, v) 的初始值为(0, 0),这就是我们对iv 的定义。 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

就这么简单:o 的定义中的(x, y) 实际上在where 子句的范围内。你甚至可以决定合并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)

另外,我可以建议您在应用程序中使用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

【讨论】:

  • 非常感谢!这很有意义!
【解决方案2】:

你想要:

  1. 构造一个列表[(u, v)],该列表的头部等于(0, 0)
  2. 然后是map 这个列表和函数\(u, v) -&gt; (u^2 - v^2 + x, 2 * u * v + y),将这个函数的结果附加到列表中。

我们可以这样写这个函数:

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

【讨论】:

  • 您确定这与基于iterate 的解决方案一样高效吗?
猜你喜欢
  • 2015-03-10
  • 2015-01-10
  • 2011-08-16
  • 2016-09-11
  • 1970-01-01
  • 1970-01-01
  • 2019-06-03
  • 1970-01-01
  • 2011-07-16
相关资源
最近更新 更多