首页 文章

是否可以将flip实现为Scala函数(而不是方法)

提问于
浏览
5

作为学习Scala的一部分,我尝试在Scala中实现Haskell的翻转函数(具有签名(A => B => C)=>(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 where(Any,Any)=>任何预期 . 但是,我不知道如何解决这个问题 . 有可能吗?

1 回答

  • 6

    与不同的方法不同,Scala不支持多态函数 . 这是由于函数的第一类值性质,它们只是 FunctioN 特征的实例 . 这些函数是类,它们需要在声明站点绑定类型 .

    如果我们采用 flip 方法并尝试将其扩展为函数,我们会看到:

    val flipFn = flip _
    

    我们将返回一个类型的值:

    ((Nothing, Nothing) => Nothing) => (Nothing, Nothing) => Nothing
    

    由于没有绑定任何类型的事实,因此编译器转向按钮类型 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))
    }
    

    flipFunctionN trait没什么不同,它定义了一个将被调用的 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
    

相关问题