Haskell中的递归Fixpoint函数

时间:2019-10-26 23:06:09

标签: haskell

我正在尝试创建一个函数,该函数查找函数f(在x = f x的情况下)的固定点,同时保持值列表的递归调用。我在将递归调用追加到上一个列表的过程中遇到了麻烦。到目前为止,这是我的代码-谢谢!

fixpointL :: (Int -> Int) -> Int -> [Int]
fixpointL f x | x == (f x) = [x]
              | otherwise = [x ++ fixpointL f (f x)]

2 个答案:

答案 0 :(得分:5)

您没有分享完全不起作用的内容-Haskell(或更确切地说,GHC)的编译时错误有时看起来有些难以理解,但如果您知道如何解释它们,则总是充满信息。这里的错误是:

<interactive>:4:30: error:
    * Couldn't match expected type `[Int]' with actual type `Int'
    * In the first argument of `(++)', namely `x'
      In the expression: x ++ fixpointL f (f x)
      In the expression: [x ++ fixpointL f (f x)]

<interactive>:4:30: error:
    * Couldn't match expected type `Int' with actual type `[Int]'
    * In the expression: x ++ fixpointL f (f x)
      In the expression: [x ++ fixpointL f (f x)]
      In an equation for `fixpointL':
          fixpointL f x
            | x == (f x) = [x]
            | otherwise = [x ++ fixpointL f (f x)]

如您所见,类型不匹配有两个不同的错误-但实际上它们密切相关。两者都很清楚到底出了什么问题。

在第一个中,它抱怨x中的x ++ fixpointL f (f x)应该是[Int]Int的列表),但实际上是{ {1}}。这很有道理-Int是赋予该函数的第二个参数,类型签名宣称该参数为x。但是您正在尝试对其应用Int运算符,并且该运算符的类型为:

(++)
  • 即,它接受两个列表(可以容纳任何元素),并返回另一个相同类型的列表。 Prelude> :t (++) (++) :: [a] -> [a] -> [a] 当然不是列表,因此也难怪GHC无法理解这一点。

第二个错误-告诉您表达式Int应该是x ++ fixpointL f (f x),但实际上是一个列表(Int)。后者是因为它实际上是在假装您将解决第一个错误,并将[Int]放入期望的x中-这样,表达式[Int]的确是{{1}的列表} s(即x ++ fixpointL f (f x))。但是,您已经将其括在方括号中:

Int

表示仅包含一个元素的列表,该元素为[Int],正如我刚才解释的那样,当前假定其类型为[x ++ fixpointL f (f x)] 。但是,由于这是函数的返回值,并且您已将返回类型声明为x ++ fixpointL f (f x),所以这意味着[Int]的内容必须为零个或多个值(在这种情况下为一个),类型为[Int]。这样可以解释另一种类型的不匹配。

我们如何解决它们?看来您想获取[...]的输出-我们假设它是Int的列表(您的类型签名表明是这样,因此GHC必须假定)。并将起始值fixpointL f (f x)附加到它的前面。假设要使用Int运算符,则正确的编写方式如下:

x

这将获取仅包含(++)的单例列表以及递归调用的结果,并将它们放到一个列表中。这种类型的检查,编译和运行符合预期:

[x] ++ fixPointL f (f x)

(很明显,在第二个示例中,我会尽快将其杀死,在我可以使用之前,实际输出要长得多,但是您明白了。)

可以改善功能的最后一种方法是使用“ cons”运算符x,其目的是在列表的开头添加元素,而无需首先构造单例列表。由于Haskell的列表是简单的链接列表,其中每个元素都包含指向下一个的指针,因此这始终是一种高效的操作(与将项目追加到末尾相对,后者花费的时间与列表的长度成正比)。尽管此处的性能差异很小,但仍被认为是惯用的。这是正常的工作版本:

Prelude> fixpointL (^2) 1
[1]
Prelude> fixpointL (*2) 1
[1,2,4,8,16,32,64,128,256,512,...]

答案 1 :(得分:1)

检查类型:

x :: Int
fixpointL f (f x) :: [Int]
(++) :: [a] -> [a] -> [a]
x ++ fixpointL f (f x) :: ??????????
[????] :: ?????

该行应为x : fixpointL f (f x)

请记住,我尚未测试过,您可以发布要测试的功能吗?