Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

switch function and object with scalaz' |>

Tags:

scala

scalaz

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.
like image 865
ryskajakub Avatar asked Jan 15 '11 13:01

ryskajakub


1 Answers

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.

like image 86
huynhjl Avatar answered Sep 17 '22 15:09

huynhjl