Function 我可以将任意函数传递给Scala中的另一个函数吗?

Function 我可以将任意函数传递给Scala中的另一个函数吗?,function,scala,functional-programming,polymorphism,arity,Function,Scala,Functional Programming,Polymorphism,Arity,我是Scala新手,能够将函数传递给其他函数非常简单——但是我能将任意函数引用传递给另一个函数吗?所述函数参数的算术将是固定的(也就是说,我也很好奇是否可以用任意算术传递函数)。我总是被类型错误绊倒。我试过使用任何,但似乎没有帮助 例如,我的代码如下: class CodeRunner(val user_defined: (Int) => Unit) { def run(input: Int) = { user_defined(input) } } def arbitra

我是Scala新手,能够将函数传递给其他函数非常简单——但是我能将任意函数引用传递给另一个函数吗?所述函数参数的算术将是固定的(也就是说,我也很好奇是否可以用任意算术传递函数)。我总是被类型错误绊倒。我试过使用
任何
,但似乎没有帮助

例如,我的代码如下:

class CodeRunner(val user_defined: (Int) => Unit) {
  def run(input: Int) = {
    user_defined(input)
  }
}

def arbitrary_code(input: Int) = { println("Running with input " + input) }

val d1 = new CodeRunner(arbitrary_code)

d1.run(4)
我得到:

Running with input 4
现在,假设我想传递以下函数:

def arbitrary_code(input: String) = { println("Running with input " + input) }
如何更改我的
CodeRunner
类来处理这两个问题

我可以将任意函数引用传递给另一个函数吗?所述功能参数的算术性将是固定的

和往常一样,写下你正在开发的函数的类型,一切都会变得清晰起来

“任意”一词表示函数参数可以在任何类型下工作。也就是说,它们是多态函数(在某些语言中是泛型函数)

以下内容应相当清晰地转换为Scala:

== The type of an "arbitrary" function of fixed arity
f :: a -> b -> c -> d

-- The type of a function that accepts such a
-- function as an argument, and does something with it:
g :: (a -> b -> c -> d) -> a -> b -> c -> d

-- And a function that implements something of that type
g f a b c = f a b c
您可能会想出一些其他的高阶函数,它们采用固定算术的函数,但具有任意(即多态)类型,并对它们进行操作

经典的高阶函数包括:

map :: (a -> b) -> [a] -> [b]

fold :: (a -> b -> b) -> b -> [a] -> b
还有很多很多其他的

如何更改我的
CodeRunner
类来处理这两个问题

您可以将任意类型设置为类的参数:

class CodeRunner[T](val user_defined: (T) => Unit) {
  def run(input: T) = {
    user_defined(input)
  }
}

def arbitrary_code(input: Int) = { println("Running with input " + input) }

val d1 = new CodeRunner(arbitrary_code)

d1.run(4)

def arbitrary_code2(input: String) = { println("Running with input " + input) }

val d2 = new CodeRunner(arbitrary_code2)

d2.run("hello")

请注意,
d2
的类型是
CodeRunner[String]
,它不能分配给
d1
,后者是
CodeRunner[Int]
,泛型类型,允许您使用占位符类型定义一个类,该占位符类型在对象实例化时指定。编译器很高兴,因为它可以确保所有内容都是类型安全的,而您很高兴,因为您可以实例化对象并为值传入任意类型

要在类中使用泛型类型,可以对其进行如下修改:

class CodeRunner[T] (val user_defined: (T) => Unit) {
  def run(input: T) = {
    user_defined(input)
  }
}
“class CodeRunner”后面的[T]是重要的部分——它定义了一个泛型类型T(可以用另一个大写字母等替换T),它将在类定义中使用

因此,如果定义一种方法:

def arbitrary_code(input: String) = { println("Running with input " + input) }
然后把它传进来:

val d1 = new CodeRunner(arbitrary_code)
。。。编译器然后说“啊哈,对于CodeRunner的这个实例,泛型类型T是一个字符串”。如果你调用

d1.run("string")

编译器会很高兴,但不会让您传入d1。运行(4)。

要传递任意函数,您当然可以使用泛型:

def run[T,U](f: T => U) = println(f)
对于任意算术,这是不可能的,因为T=>U类型的函数是Function1[U,T]的实例,而(T,U=>V类型的函数是Function2[T,U,V]的实例。(另外,我也找不到任何有用的用例)。 然而,有一个聪明的概念叫做“咖喱”。它包括转换接受多个参数并在接受单个参数并返回另一个函数的函数中返回值的函数。 下面是一个例子:

def nonCurriedAdd(x: Int, y: Int) = x + y
// nonCurriedAdd(4,6)
def curriedAdd(x: Int) = (y: Int) => x + y
// we can use some syntax sugar
def curriedAdd(x: Int)(y: Int) = x + y
// curriedAdd(4)(6)
现在,您可以执行'd1.run(curriedAdd)。 您还可以使用“curried”方法将非curried函数转换为curried函数:

闻起来像是仿制药。有人指出后,这似乎很明显。谢谢
def nonCurriedAdd(x: Int, y: Int) = x + y
// nonCurriedAdd(4,6)
def curriedAdd(x: Int) = (y: Int) => x + y
// we can use some syntax sugar
def curriedAdd(x: Int)(y: Int) = x + y
// curriedAdd(4)(6)
d1.run(nonCurriedAdd.curried)