문제

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.

도움이 되었습니까?

해결책

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.

다른 팁

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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top