How can I improve Scala type output with type parameters that do not appear in the first parameter list?

To illustrate my point, here is an example:

abstract class Wrapper[A](wrapped: A) { protected def someCondition: Boolean def fold[B](whenTrue: => B)(whenFalse: => B): B = if (someCondition) whenTrue else whenFalse } 

I am trying to add a fold method based on an arbitrary condition defined on wrapped type A The problem with the above code is that this did not compile, although it is possible to possibly return Any :

 wrapper.fold("hi")(42) 

because by the time the compiler reaches the second parameter list, B has already been output as String . Suppose we do not want to write a type annotation. We can try changing fold to this:

 def fold[B, B0 >: B](whenTrue: => B)(whenFalse: => B0): B0 

but this also does not work, since B0 already resolved as a String at the end of the first parameter list, although it does not appear at all in it! A simple solution, of course, is to have a single list of parameters, but, for the sake of example, let's say I want to save two lists of parameters and try to make it work ... Ideally, we should be able to delay the resolution of B0 . It would be great if we could write something like this:

 def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0 

But, unfortunately, this does not work. Are there any workarounds?

(I give the first answer, but of course I am looking for other workarounds).

+6
source share
2 answers

One solution is to create a temporary instance of the class that defines the apply method, which simulates a second list of parameters, which itself has a parameter of type B0 :

 abstract class Wrapper[A](wrapped: A) { // ... as before... def fold[B](whenTrue: => B) = new FoldRequest[B](whenTrue) class FoldRequest[B](whenTrue: => B) { def apply[B0 >: B](whenFalse: => B0) = if (someCondition) whenTrue else whenFalse } } 

Then everything works correctly. Is it even possible to imagine that def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0 can be interpreted as syntactic sugar for this? ...

+3
source

It seems you want to emulate, thanks to the compilation, behavior and purpose of the Either class. You can do the following: your summary will return an Either object and get the value B0 from it:

 abstract class Wrapper[A](wrapped: A) { protected def someCondition: Boolean def fold[A, B](whenTrue: => B)(whenFalse: => A): Either[A, B] = Either.cond(someCondition, whenTrue, whenFalse) } 

And let the implicit conversion of either2mergeable of the Either class do the job:

 scala> new Wrapper[Unit] {def someCondition = true} res0: Wrapper[Unit] = $anon$1@77026e40 scala> res0.fold(42)("hi").merge res1: Any = 42 

Pro:

  • The Either structure allows you to directly extract types A and B
  • You can check which part was applied during the reset.

Con:

  • You do not get the result directly
+5
source

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


All Articles