Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implicitly convert an object with an appropriate apply method to a function?

Tags:

scala

As the question says I am trying the following (does not compile):

  object O {
    def apply(i: Int): Boolean = i % 2 == 0
  }
  val f: Int => Boolean = O

So I tried this:

  implicit def apply2Fct[A,B](applier: { def apply(a: A): B }) = {
    new Function[A,B] { def apply(a: A): B = applier(a) }
  }

But the compiler complains about "Parameter type in structural refinement may not refer to an abstract type defined outside that refinement".

EDIT :

Due to the answer of Jean-Philippe Pellet I have to mention that I can´t let O extend Function[A,B] respectively Function[Int,Boolean].

like image 749
Peter Schmitz Avatar asked Jan 30 '26 23:01

Peter Schmitz


1 Answers

You can't do this directly for the reasons that Gilles gives on ticket #967. The problematic construct is the occurrence of the externally defined type parameter A in a bare argument position on a method definition within the structural type.

However, we can approximate the desired result by eliminating the problematic occurrence in favour of an internal type parameter coupled with a type constraint forcing it to be equal to the original argument type A at any point at which the method is applied.

To do this you have to modify the general form of the signatures of the methods you're trying to capture structurally from (nb. pseudocode follows),

def method(x : <<your arg type>>) : <<your result type>>

to

def method[T](x : T)(implicit ev : T =:= <<your arg type>>) : <<your result type>>

For your particular case we would need something like the following,

object O {
  def apply[T](i : T)(implicit ev : T =:= Int) : Boolean = i % 2 == 0
}

implicit def apply2Fct[A,B](applier: { def apply[T](a: T)(implicit ev : T =:= A): B }) = {
  new Function[A,B] { def apply(a: A): B = applier(a) }
}

Sample REPL session,

scala> implicit def apply2Fct[A,B](applier: { def apply[T](a: T)(implicit ev : T =:= A): B }) = {
     | new Function[A,B] { def apply(a: A): B = applier(a) }
     | }
apply2Fct: [A, B](applier: AnyRef{def apply[T](a: T)(implicit ev: =:=[T,A]): B})java.lang.Object with (A) => B

scala> object O {
     | def apply[T](i : T)(implicit ev : T =:= Int) : Boolean = i % 2 == 0
     | }
defined module O

scala> O(23)
res0: Boolean = false

scala> O(24)
res1: Boolean = true

scala> val f: Int => Boolean = O
f: (Int) => Boolean = <function1>                                                                                                                                                                                                              

scala> f(23)                                                                                                                                                                                                                                   
res2: Boolean = false                                                                                                                                                                                                                          

scala> f(24)                                                                                                                                                                                                                                   
res3: Boolean = true  
like image 133
Miles Sabin Avatar answered Feb 01 '26 14:02

Miles Sabin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!