我是Haskell的业余爱好者,试图通过"x"的平方根的无限近似列表,其中"acc"代表这一步的生成.但是,当我运行下面的代码时,我得到了潜在的错误.
as' x acc = ( last(take (acc-1) (as' x (acc-1)))
+ (acc / last(take (acc-1) (as' x (acc-1)))) ) / 2 : as' x (acc+1)
Run Code Online (Sandbox Code Playgroud)
ERROR "a5.hs":34 - Instance of Fractional Int required for definition of as'
此外,当我尝试应用此类型代码时,我收到一个错误:
as' :: Float -> Float -> Float
Run Code Online (Sandbox Code Playgroud)
Type error in application
*** Expression : (last (take (acc - 1) (as' x (acc - 1))) + acc / last (take (acc - 1) (as' x (acc - 1)))) / 2 : as' x (acc + 1)
*** Term : as' x (acc + 1)
*** Type : Float
*** Does not match : [a]
编辑:为了给你一些清晰度,我想在列表的上下文中使用此功能.例如,当x = [1,为'x 2]时.这个想法是,这将积累一个无限的列表,因为'将递归地调用自己.因此,为什么我觉得我可以在列表上操作.
有人可以给我一些清晰度吗?
dav*_*420 12
类型签名take是
take :: Int -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
以下是您的使用方法take:
take (acc-1) (as' x (acc-1))
Run Code Online (Sandbox Code Playgroud)
所以我们可以得出结论
(acc-1) :: Int -- first parameter to `take`
acc :: Int -- therefore
(as' x (acc-1)) :: [a] -- second parameter to `take`, we don't know what `a` is
Run Code Online (Sandbox Code Playgroud)
但是你的代码说
as' :: Float -> Float -> Float
as' x acc = ...
Run Code Online (Sandbox Code Playgroud)
我们从中推断出
x :: Float -- first parameter to `as'`
acc :: Float -- second parameter to `as'`
(as' x (acc-1)) :: Float -- result of `as'`
Run Code Online (Sandbox Code Playgroud)
这导致了几个矛盾:
acc不可能是一个Int和一个Float同时(as' x (acc-1))不能是a [a]和a Float同时---这是第二条错误消息试图告诉你的最终,您正在尝试使用take不是列表的东西.我不确定你要做什么.
您可能打算签名
as' :: Float -> Int -> [Float]
Run Code Online (Sandbox Code Playgroud)
这应该(我没有测试它)修复类型错误之上,但仍留下一个更根本的问题:当你计算ñ个列表的元素,你计算*列表中的n-1个*个元素重新两次(依此类推,回到列表的开头:重新计算的指数增长),尽管可能已经计算了这个元素.没有共享.
例如考虑
as' x acc = ( prev + (acc / prev) ) / 2 : as' x (acc+1)
where prev = last(take (acc-1) (as' x (acc-1)))
Run Code Online (Sandbox Code Playgroud)
这仍然是低效的:您仍然重新计算列表的先前元素.但现在,您只需在计算下一个元素时重新计算所有先前的元素.
(我也不能指出我last(take (acc-1) (as' x (acc-1)))可以简化为(as' x (acc-1)) !! (acc-2).)
生成无限列表的常用方法是使用每个元素仅依赖于前一个元素iterate.
复杂的是,每个元素都取决于累加器以及前一个元素.我们将把累加器合并到列表的每个元素中.当我们完成后,我们将丢弃累加器以产生我们的最终无限列表.
approxRoots :: Float -> [Float]
approxRoots x = map fst $ iterate next (x, 1)
-- I don't know what your initial approximation should be
-- I've put `x` but that's probably wrong
where next (prev, acc) = (prev + acc / prev, acc + 1)
-- First element of each pair is the approximation,
-- second element of each pair is the "accumulator" (actually an index)
-- I've probably transcribed your formula wrongly
Run Code Online (Sandbox Code Playgroud)
dave4420的答案已经非常好了,我只是想分享一下如何从编译器给你的错误信息中获得最大的收益.这是它:
*** Expression : (last (take (acc - 1) (as' x (acc - 1))) + acc / last (take (acc - 1) (as' x (acc - 1)))) / 2 : as' x (acc + 1)
*** Term : as' x (acc + 1)
*** Type : Float
*** Does not match : [a]
Run Code Online (Sandbox Code Playgroud)
这意味着as' x (acc + 1)long表达式中的部分预计会产生一个列表,但实际上它给出了一个Float值.
为什么编译器希望它是一个列表?好吧,让我们看一下表达式中术语的用法:
(last .... ) / 2 : as' x (acc + 1)
Run Code Online (Sandbox Code Playgroud)
即,它是作为第二个参数的(:)函数,编译器知道第二个参数给这个函数必须是一个列表(编译器知道的签名 (:)是a -> [a] -> [a],虽然它并没有提到在错误信息的那部分) .
它为什么实际上是一个Float?由于您没有提供函数签名,编译器会为您推导出它并实际打印它:
as' :: Float -> Float -> Float
Run Code Online (Sandbox Code Playgroud)
因此编译器确定as'采用两个Float值并产生一个Float值.我不知道为什么会这样做.
我的建议是通过自己明确地写下函数签名来开始调试这个问题.这样做会导致出现不同的错误消息,这更接近于您的期望与实际代码之间不匹配的原因.