我目前正在完成Martin Odersky的Coursera课程,Scala中的功能编程原理的视频讲座。在讲座2.1中,他使用基函数sum()
演示了高阶函数的组合。他实现了没有尾递归的阶乘,但我尝试使用尾递归,因为它仍然只是一行代码。结果,我得到了一个类型不匹配,我认为Odersky没有。在定义sum()
时,参数f
需要Int
并返回Int
。我知道我可以通过调整我的函数*来解决这个问题,但这让我想知道如何设计更高阶的函数。 有没有办法可以调整或规避这种类型定义,以便允许带有灵活数量参数的函数?有人向我展示了一次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经验的印象是,函数式编程提升函数只需要一个参数来允许currying。无论如何,它与实际问题有点相关,但如果我只是用我的问题的精神可怜地屠杀FP,请随时在评论中解决这个问题。
答案 0 :(得分:2)
我认为这里有几件事情。
首先,我认为您正在尝试使用事实函数(使用具有默认值的函数,就好像它的类型实际上只有少一个参数)是不可能的。 (Int,Int)=> Int仍然是(Int,Int)=>即使第二个Int默认为1,也不能将其作为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)
你也不能把和作为:
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)
请注意,我们必须切换事实参数的位置。