Question

I can use scalaz |> operator when I want to switch function and object so there can be a little more readability acquired. Let me introduce you a model function :

def length2(x:String) = x.length * 2
Now, I can write it in both ways:
"aoeu" |> length2
length2("aoeu")
But if I define this function more generic, it stops working.
def length2(x:SeqLike[_,_]) = x.length * 2
length2("aoeu") // ok
"aoeu" |> length2 // doesn't work
Why the compiler doesn't understand this? There is definitely an implicit conversion from String to some class mixing in trait SeqLike.

Was it helpful?

Solution

scala> "aoeu" |> length2
<console>:14: error: type mismatch;
 found   : (scala.collection.SeqLike[_, _]) => Int
 required: (java.lang.String) => ?
       "aoeu" |> length2

The error message is pretty clear.

Although there is an implicit conversion from String to SeqLike[_,_], there is no conversion from (SeqLike[_, _]) => Int to String => ?.

This can be fixed using the following implicit conversion:

implicit def liftFun[X, T <% X, U](f: (X) => U): (T) => U = {
  def g(t:T) = f(t)
  g _
}

Edit 2: here is a non-scalaz operator.

class Pipe[T](t:T) {
  def |%>[X, U](f: (X) => U)(implicit ev: T <%< X) = f(t)
}
implicit def toPipe[T](t:T) = new Pipe(t:T)

Then you can use it like this:

def l1(a:String) = a.length
def l2(a:Seq[_]) = a.length * 2

"abc" |%> l1
"abc" |%> l2

It allows |%> to take a function that does not work directly on a T but on a X as long as there is evidence of an implicit conversion from T to X.

OTHER TIPS

Do not use existential types unless necessary. They break things, and are not required here.

On the other hand, seeing in the error in the other answer made things more clear. You there are two implicit conversions being asked for when you use |>. Does it work if you declare it like this instead:

def length2[CC <% SeqLike[_, _]](x: CC) = x.length * 2
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top