Is it possible to implement flip as a Scala function (and not a method)

As part of Scala training, I am trying to implement the Haskell flag function (function with signature (A => B => C) => (B => A => C)) in Scala - and implement it as a function (using val), not as a method (using def).

I can implement it as a method, for example, as follows:

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

However, when I try to implement it as a function, it does not work:

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

When I try to compile this code, it does not work with this message:

 Error:(8, 18) type mismatch; found : (Int, Int) => Int required: (Any, Any) => Any val f = flip(minus) 

I understand why it fails: I'm trying to pass (Int, Int) => Int where (Any, Any) => Any is expected. However, I do not know how to solve this problem. Is it possible at all?

+5
source share
1 answer

Scala does not support polymorphic functions, unlike methods. This is due to the first-class character value of functions that are just instances of FunctioN traits. These functions are classes, and they need types to be bound on the ad site.

If we take the flip method and try to extend it to a function, we will see:

 val flipFn = flip _ 

We will return a value like:

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

Due to the fact that none of the types was connected, therefore, the compiler refers to the buttom Nothing type.

However, not all hope is lost. There is a library called shapeless that allows us to define polymorphic functions through PolyN .

We can implement flip as follows:

 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 is no different from the FunctionN attribute; it defines the apply method that will be called.

We use it as follows:

 def main(args: Array[String]): Unit = { val minus = (a: Int, b: Int) => a - b val f = flip(minus) println(f(3, 5)) } 

Yielding:

 2 

This also works for String :

 def main(args: Array[String]): Unit = { val stringConcat = (a: String, b: String) => a + b val f = flip(stringConcat) println(f("hello", "world")) } 

Yielding:

 worldhello 
+6
source

Source: https://habr.com/ru/post/1271695/


All Articles