我目前正在研究Martin Odersky的Coursera课程的视频讲座,即Scala中的Functional Programming Principles。在第2.1课中,他演示了使用基函数构成高阶函数的过程sum()
。他实现了无尾递归的阶乘,但我还是尝试了尾递归,因为它仍然只是一行代码。结果,我认为Odersky没有类型不匹配。在定义中sum()
,参数f
取一个,Int
然后返回一个Int
。我知道我可以通过调整我的function *来解决这个问题,但这让我想知道一般如何设计高阶函数。有没有一种方法可以调整或规避此类型定义,以允许使用灵活数量的参数的函数?有人给我看过一点Haskell,我想知道Scala的函数参数是否可以以类似的松散方式键入……或者也许还有另一种解决方案更原始于Scala。请假设我昨天才刚开始与Scala一起玩,并且在您的解释中对计算机科学的知识有限,因为确实如此。
def sum(f: Int => Int, a: Int, b: Int): Int =
if (a > b) 0 else f(a) + sum(f, a+1, b)
//Factorial with tail recursion. The one in the lesson DOES NOT use tail recursion.
//prev is an accumulator.
def fact(a: Int, prev:Int = 1): Int =
if (a == 0) prev else fact(a-1, a * prev)
def sumFactorials(a: Int, b: Int): Int = sum(fact, a, b)
*我知道我可以通过将当前内容嵌套fact()
在另一个函数中来解决此问题,如下所示:
def factorial(a: Int): Int ={
def fact(n: Int, prev:Int = 1): Int =
if (n == 0) prev else fact(n-1, n * prev)
fact(a)
}
从我之前在Haskell的经验中得出的印象是,函数式编程仅使用一个参数就可以促进函数化,从而促进了函数的使用。无论如何,这与实际问题有些关系,但是如果我只是以问题的精神来疯狂屠杀FP,请随时在评论中解决此问题。
我认为这里发生了几件事。
首先,我认为您无法处理事实函数(使用具有默认值的函数,就好像其类型实际上少了一个参数)是不可能的。即使第二个Int默认为1,一个(Int,Int)=> Int仍然是(Int,Int)=> Int。您不能将其作为Int => Int传递。不过,我可以看到您可能会想到的地方。
其次,事实和阶乘函数不相等。不管递归多少次,阶乘函数都会反复使用'a'的原始值。事实函数在每个调用中使用减量“ a”。
根据您的“固定”阶乘函数,该函数有效地采用了三个参数:原始a,减n和乘以prev。以下代码是等效的。
def sum(f: (Int,Int,Int) => Int, a: Int, b: Int): Int =
if (a > b) 0 else f(a,a,1) + sum(f, a+1, b)
def fact(a: Int, n: Int, prev:Int): Int =
if (n == 0) prev else fact(a, n-1, a * prev)
def sumFactorials(a: Int, b: Int): Int = sum(fact, a, b)
您也不能将sum编写为:
def sum(f: (Int, Int) => Int, a: Int, b: Int): Int =
if (a > b) 0 else f(a) + sum(f, a+1, b)
传入的函数f可能具有默认参数,但可能没有默认参数,因此编译器允许f(a)调用并不安全。
我认为默认参数的实现更像是“语法糖”,就像他们所说的那样,附加在实际函数上,而不是像函数currying那样。您可以使用currying进行此操作,但是必须显式声明curried函数。假设您要使用事实逻辑(而不是阶乘逻辑),可以这样做:
def sum(f: Int => Int, a: Int, b: Int): Int =
if (a > b) 0 else f(a) + sum(f, a+1, b)
def fact(prev:Int = 1)(a: Int): Int =
if (a == 0) prev else fact(a * prev)(a-1)
def sumFactorials(a: Int, b: Int): Int = sum(fact(1), a, b)
请注意,我们必须切换事实参数的位置。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句