funzione di interruttore e oggetto con scalaz' |>
Domanda
posso usare scalaz
operatore |>
quando voglio funzione di interruttore e l'oggetto così non ci può essere un po 'più leggibilità acquisita. Lasciate che vi presenti una funzione del modello:
def length2(x:String) = x.length * 2
ora, posso scrivere in entrambi i modi: "aoeu" |> length2
length2("aoeu")
Ma se io definisco questa funzione più generica, si ferma working.def length2(x:SeqLike[_
,_
]) = x.length * 2
length2("aoeu") // ok
"aoeu" |> length2 // doesn't work
Perché il compilatore non capisce questo? C'è sicuramente una conversione implicita da String
a qualche classe di miscelazione in SeqLike
tratto.
Soluzione
scala> "aoeu" |> length2
<console>:14: error: type mismatch;
found : (scala.collection.SeqLike[_, _]) => Int
required: (java.lang.String) => ?
"aoeu" |> length2
Il messaggio di errore è abbastanza chiaro.
Anche se v'è una conversione implicita da String
a SeqLike[_,_]
, non v'è alcuna conversione da (SeqLike[_, _]) => Int
a String => ?
.
Questo può essere risolto utilizzando la seguente conversione implicita:
implicit def liftFun[X, T <% X, U](f: (X) => U): (T) => U = {
def g(t:T) = f(t)
g _
}
Modifica 2 :. Qui è un operatore non scalaz
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)
Quindi è possibile utilizzare in questo modo:
def l1(a:String) = a.length
def l2(a:Seq[_]) = a.length * 2
"abc" |%> l1
"abc" |%> l2
Permette |%>
di prendere una funzione che non funziona direttamente su una T
ma su un X
fintanto che non v'è evidenza di una conversione implicita da T
a X
.
Altri suggerimenti
Non utilizzare tipi esistenziali se non necessario. Si rompono le cose, e non sono necessari qui.
D'altra parte, vedendo in errore nel altra risposta ha reso le cose più chiare. Voi ci sono due conversioni implicite viene chiesto per quando si utilizza |>
. Funziona se si dichiara in questo modo invece:
def length2[CC <% SeqLike[_, _]](x: CC) = x.length * 2