如何在Haskell中解决此数学函数?

时间:2018-12-20 21:03:51

标签: haskell

如何使用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中此问题需要两个或三个循环。

2 个答案:

答案 0 :(得分:8)

我通常会给出提示而不是完整的解决方案,但是由于这个问题主要是关于语法的,而且翻译非常接近,几乎是字面意义,因此我将其完整地提供给您。

math thing

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以外的其他第一个自变量的干净概括。答案是肯定的。基本思想是:由于transposezip到任意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)