在更高阶函数中键入定义和类型不匹配

时间:2013-11-04 04:18:10

标签: scala recursion types function-composition

我目前正在完成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,请随时在评论中解决这个问题。

1 个答案:

答案 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)

请注意,我们必须切换事实参数的位置。