如何使用Haskell解决此数学函数? 谁能帮我吗?
https://www.notebook.hu/notebook/acer-notebook/aspire-sorozat
myFunc n m = myFuncRec n m if m <= n then 1
else myFuncRec n(m - 1):[]
我需要两次递归吗?因为在Java中此问题需要两个或三个循环。
答案 0 :(得分:8)
我通常会给出提示而不是完整的解决方案,但是由于这个问题主要是关于语法的,而且翻译非常接近,几乎是字面意义,因此我将其完整地提供给您。
p n m
| m <= n = 1
| otherwise = sum [ p n (m - i) | i <- [1..n] ]
按条件区分不同情况的横线称为后卫,最后一行的括号结构称为列表理解。
答案 1 :(得分:4)
luqui的答案将数学定义自然而直接地转换为Haskell代码。作为一个规范,它是完美的:美丽且显然正确。作为一种教学工具,它是完美的:易于阅读,易于理解,并且不使用任何高级功能。但是作为一个算法,它有点不幸:每个递归调用都存在许多递归调用,这对于大输入量来说非常慢。因此,在这个答案中,我将介绍一下并非旨在简化的解决方案。
一个有趣的发现是P(2,-)
是斐波那契数列,它在Haskell中具有无穷列表的众所周知,优美而有效的定义:
fibs = 1:1:zipWith (+) fibs (tail fibs)
此递归定义的列表将其自身用作备注表。也许有人会问,这个技巧对P是否具有除2以外的其他第一个自变量的干净概括。答案是肯定的。基本思想是:由于transpose
是zip
到任意Arity的自然扩展,而sum
是(+)
到任意Arity的自然扩展,我们可以这样写:
import Data.List
transposeWith :: ([a] -> b) -> [[a]] -> [b]
transposeWith f xss = map f (transpose xss)
genFib :: Int -> [Integer]
genFib n = result where
result = replicate n 1 ++ transposeWith sum [drop i result | i <- [0..n-1]]
这为我们提供了一种有效的方法,即使用清单进行备忘录来为任何P(n,-)
计算n
。如果我们甚至想记住n
维度,我们可以写:
p :: [[Integer]]
p = map genFib [1..]
速度快多少?在我的机器上,计算P(100, 130)
花费了luqui的解决方案超过十分钟(并且每次向m
添加一个时,时间大约会翻倍),而即使这样,我的解决方案也能在一秒钟内响应大输入为P(100, 10000)
。