我在博客上搜索了一个与我想要的类似的Fibonacci实现。尽管有很多关于Haskell的Fibonacci实现的问题,但没有出现任何问题。
我想要一个递归的Fibonacci函数(速度无关紧要),它会在每次调用fib函数时将每个Fibonacci数附加到全局列表中。我是Haskell的新手,来自一个势在必行的背景。这是我认为可行的,但没有达到目的。
fibos = []
fib 0 = 1
fib 1 = 1
fib n = (fib(n-1) + fib(n-2)):fibos
main = do
putStrLn "Please enter a number:"
n <- readLn
fib n
print fibos
我知道Haskell中已经存在的Fibonacci列表,但是我的赋值规范要求我这样做。我试图将每个Fibonacci数字提升到用户定义的数字n到空的全局fibos列表中。任何帮助或指示将不胜感激。
编辑:
我现在有一个工作函数,它返回一个包含n个元素的斐波纳契数列表,其中n是用户输入,这里是代码:
fib::Int->Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
fibList n = map fib [0..n]
main :: IO ()
main = do
putStrLn "Please enter a positive integer:"
n <- readLn
print (fibList n)
我需要的是一个函数,如果用户输入2则输出[0,1,1,2],如果用户输入8或8之间的任何内容则输出[0,1,1,3,3,5,8]和12(因为13是一个纤维数)。
答案 0 :(得分:2)
import Data.List
fibo :: Int -> Int
fibo 0 = 0
fibo 1 = 1
fibo n = fibo (n-1)+fibo(n-2)
fiboList x =map fibo [1..x]
main = do
print ( fiboList 35 )
答案 1 :(得分:1)
修改强>
如果只需要查看导致fib n
的值序列,您应该使用以下内容:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
fib n = (take n fibs, fibs !! n)
的工作原理如下:
*Main> fib 0
([],0)
*Main> fib 1
([0],1)
*Main> fib 10
([0,1,1,2,3,5,8,13,21,34],55)
如果需要,可以使用State monad来分离计算的列表方面,但它只是指在有限范围内“全局”的列表(例如main
函数)。这是你住在适当的Haskell土地时最接近你想要的。
正确的方式
我假设你是为了模仿的目的而尝试这个?如果是,基本上已经存在fib
的任何基于列表的实现的全局列表 - 任何fib
的调用者使用与Haskell(例如GHC)运行时使用的相同的延迟评估列表引擎盖;该列表中已经计算过的任何元素都不会被重新计算。
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
- 这里,fibs
是一个全局列表,而你无法通过访问其中的单个元素(fibs !! n
)来显式地/手动地改变它,你当运行时向其添加新值时间接导致底层列表发生变异。
错误的方式(但如果您不打算在实际代码中使用此功能,请继续使用)
另一方面,如果您只是为了拥有该列表而需要列表,例如出于调试或其他一些奇怪的原因,您可以使用非常丑陋且不安全的黑客,例如以下基于IORef
的解决方案,但请记住坚持以结尾的函数名称Unsafe
,本着stdlib标记所有不安全呼叫的精神,以便使用它们的人意识到危险:
import Data.IORef
import System.IO.Unsafe (unsafePerformIO)
fibsStorageUnsafe :: IORef [Integer]
fibsStorageUnsafe = unsafePerformIO $ newIORef []
-- this is one one that uses the pure definition
-- above to compute the value and then store it
-- in a global, mutable IORef
fibUnsafe n = unsafePerformIO (updateFibs ret) `seq` ret
where
ret = fib' n
updateFibs x = do
old <- readIORef fibsStorageUnsafe
writeIORef fibsStorageUnsafe (x:old)
fib' :: Int -> Integer
fib' 0 = 0
fib' 1 = 1
-- you can recursively call fib' instead of fibUnsafe
-- to only log the "top level" (non-recursive)
-- calls to fibUnsafe and not all recursive calls
fib' n = fibUnsafe (n-1) + fibUnsafe (n-2)
的工作原理如下:
*Main> readIORef fibsStorageUnsafe
[]
*Main> fibUnsafe 0
0
*Main> readIORef fibsStorageUnsafe
[0]
*Main> fibUnsafe 1
1
*Main> readIORef fibsStorageUnsafe
[1,0]
*Main> fibUnsafe 3
2
*Main> readIORef fibsStorageUnsafe
[1,0,1,1,2,1,0]
*Main> fibUnsafe 10
55
*Main> readIORef fibsStorageUnsafe
[1,0,1,1,2,1,0,1,3,1,0,1,1,2,5,1,0,1,1,2,1,0,1,3,8,1,0,1,1,2,1,0,1,3,1,0,1,1,2,5,13,1,0,1,1,2,1,0,1,3,1,0,1,1,2,5,1,0,1,1,2,1,0,1,3,8,21,1,0,1,1,2,1,0,1,3,1,0,1,1,2,5,1,0,1,1,2,1,0,1,3,8,1,0,1,1,2,1,0,1,3,1,0,1,1,2,5,13,34,1,0,1,1,2,1,0,1,3,1,0,1,1,2,5,1,0,1,1,2,1,0,1,3,8,1,0,1,1,2,1,0,1,3,1,0,1,1,2,5,13,1,0,1,1,2,1,0,1,3,1,0,1,1,2,5,1,0,1,1,2,1,0,1,3,8,21,55,1,0,1,1,2,1,0]
您可以调整fibUnsafe
,fib'
和其他组件的定义以符合您的目标,但同样:我强烈建议不要使用这样的方法,除非它仅用于学习或实验目的。
例如,如果您修改fib'
来调用自己而不是fibUnsafe
,请执行以下操作:
fib' n = fib' (n-1) + fib' (n-2)
然后调用fibUnsafe 10
将产生fibStorageUnsafe
的以下内容,而不是您在上面看到的内容:
*Main> fibUnsafe 10
55
*Main> readIORef fibsStorageUnsafe
[55]
免责声明:我甚至不知道上述基于IORef
的代码在所有情况下是否都能正常运行 - 我承认我对IORef
s不太熟悉以及unsafePerformIO
如何工作以保证上述代码的语义。
答案 2 :(得分:1)
如果可以获得列表,你可以按照自己的意愿做一些事情:
if ($_SERVER['REQUEST_URI'] == '/?Über-uns.php'){
$html.= 'hover.navbutton-ueber-uns';
} else {
$html.= 'navbutton-ueber-uns';
}
然后fibs 0 = [0]
fibs 1 = [0,1]
fibs n = let fs@(f1:f2:_) = fibs (n-1)
in (f1+f2) : fs
将返回fibs 10
。请注意,以相反的顺序构建列表可能会浪费或更复杂,因为Haskell列表仅在“前端”上运行。对于奇怪的[55,34,21,13,8,5,3,2,1,1,0]
,请参阅https://en.wikibooks.org/wiki/Haskell/Pattern_matching(fs@(f1:f2:_)
是“as” - 模式)
对于“真正的”斐波那契函数,你只需要返回头部:
@
我认为这个版本的意图非常接近,而且它的性能也不错。但是,这段代码不是很惯用。这里的典型方法是无限列表(如其他一些答案所示)。
如果你允许我个人发表评论:我发现“必要”知识在学习Haskell时比帮助更有刺激性。我认为你应该有意识地“忘记”或“忘掉”你对(命令式)编程的了解,以便“理解”函数式编程。
答案 3 :(得分:0)
在纯函数式编程中,不能使用全局的可变变量。因此,如果您定义全局值fibos = []
,那么该列表将永远不会是空列表。如果您想要一个不可变的顶级定义,请将其修改为 n 第一个Fibonacci数字,其中 n 在运行时确定,fibs
没有参数变得困难。
另一种选择是Haskell的懒惰评估,它使您能够为所有斐波那契数字创建顶级定义,但它们只会在请求的范围内进行计算。
fibs :: [Integer]
fibs = 1:1:zipWith (+) fibs (tail fibs)
或者不那么花哨:
fibs :: [Integer]
fibs = fib 0 1
where fib a b = b : fib b (a+b)
然后,您可以根据需要提取尽可能多的斐波那契数字:
main :: IO ()
main = do
putStr "n: "
n <- readLn
putStrLn $ "Fibs: " ++ show (take n fibs)