作为学习Scala的一部分,我尝试实现Haskell的翻转功能(具有签名的功能(A => B => C)=>( Scala中的B => A => C))并将其作为函数实现(使用 val )而不是作为方法(使用 def ) )。
我可以将它作为一种方法实现,例如:
def flip[A, B, C](f: (A, B) => C):((B, A) => C) = (b: B, a: A) => f(a, b)
val minus = (a: Int, b: Int) => a - b
val f = flip(minus)
println(f(3, 5))
但是,当我尝试将其作为一个函数实现时,它不起作用:
val flip = (f: ((Any, Any) => Any)) => ((a: Any, b: Any) => f(b, a))
val minus = (a: Int, b: Int) => a - b
val f = flip(minus)
println(f(3, 5))
当我尝试编译此代码时,它会失败并显示以下消息:
Error:(8, 18) type mismatch;
found : (Int, Int) => Int
required: (Any, Any) => Any
val f = flip(minus)
我明白为什么它会失败:我尝试传递(Int,Int)=> Int 其中(Any,Any)=>任何都是预料之中的。但是,我不知道如何解决这个问题。它有可能吗?
答案 0 :(得分:6)
Scala不支持多态函数,不像那些方法。这是由于函数的第一类值性质,它们只是FunctioN
特征的实例。这些函数是类,它们需要在声明站点绑定类型。
如果我们采用flip
方法并尝试将其扩展为函数,我们会看到:
val flipFn = flip _
我们会返回一个类型为
的值((Nothing, Nothing) => Nothing) => (Nothing, Nothing) => Nothing
由于没有绑定任何类型,因此编译器会转换为buttom类型Nothing
。
然而,并非所有希望都失去了。有一个名为shapeless的库允许我们通过PolyN
定义多态函数。
我们可以像这样实现翻转:
import shapeless.Poly1
object flip extends Poly1 {
implicit def genericCase[A, B, C] = at[(A, B) => C](f => (b: B, a: A) => f(a, b))
}
flip
与FunctionN
特征没有区别,它定义了一个将被调用的apply
方法。
我们这样使用它:
def main(args: Array[String]): Unit = {
val minus = (a: Int, b: Int) => a - b
val f = flip(minus)
println(f(3, 5))
}
产量:
2
这也适用于String
:
def main(args: Array[String]): Unit = {
val stringConcat = (a: String, b: String) => a + b
val f = flip(stringConcat)
println(f("hello", "world"))
}
产量:
worldhello