2011-01-15 12 views
13

Posso usare l'operatore scalaz|> quando voglio cambiare funzione e oggetto in modo da ottenere un po' più di leggibilità acquisita. Permettetemi di presentarvi una funzione modello: funzione switch e oggetto con scalaz '|>

def length2(x:String) = x.length * 2
Ora, posso scrivere in entrambi i modi:
"aoeu" |> length2 
length2("aoeu")
Ma se definisco questa funzione più generica, smette di funzionare.
def length2(x:SeqLike[_,_]) = x.length * 2 
length2("aoeu") // ok 
"aoeu" |> length2 // doesn't work
Perché il compilatore non lo capisce? Esiste sicuramente una conversione implicita da String a un mix di classe nel tratto SeqLike.

+0

Ingannevole. All'inizio ho pensato che è possibile avere un implicito alla volta ma ora sembra che sia forse anche un problema di varianza nascosto da qualche parte ... – Debilski

+2

@Debilski, non sono sicuro di dove '|>' è definito in scalaz, ma quando Ho cercato di definire il mio, penso che "l'unica regola implicita" è ciò che gli ha impedito di applicare: "aoeu" avrebbe dovuto essere convertito implicitamente alla classe con il metodo '|>' e poi di nuovo a 'SeqLike'. – huynhjl

+1

Mostra il messaggio di errore. Non tutti hanno Scalaz prontamente disponibile, ma i messaggi di errore di solito spiegano cosa non va. –

risposta

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

messaggio L'errore è abbastanza chiaro.

Sebbene vi sia 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 _ 
} 

Edit 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 

Essa permette |%> di prendere una funzione che non funziona direttamente su una T ma su un X fintanto che non v'è evidenza di un implicito conversione da T a X.

2

Non utilizzare tipi esistenziali se non necessario. Rompono le cose e non sono richieste qui.

D'altra parte, vedere l'errore nell'altra risposta ha reso le cose più chiare. Ci sono due conversioni implicite richieste quando si utilizza |>. Funziona se si dichiara in questo modo invece:

def length2[CC <% SeqLike[_, _]](x: CC) = x.length * 2 
+1

Restituisce: 'impossibile trovare il valore implicito per parametro evidence di tipo (CC) => scala.collection.SeqLike [_, _]' – huynhjl