2011-01-15 39 views
13

Puedo usar el operador scalaz|> cuando quiero cambiar la función y el objeto para que se pueda adquirir un poco más de legibilidad. Permítanme presentarles una función de modelo: cambiar la función y el objeto con scalaz '|>

def length2(x:String) = x.length * 2
Ahora, puedo escribirlo en ambos sentidos:
"aoeu" |> length2 
length2("aoeu")
Pero si defino esta función más genérica, deja de funcionar.
def length2(x:SeqLike[_,_]) = x.length * 2 
length2("aoeu") // ok 
"aoeu" |> length2 // doesn't work
¿Por qué el compilador no entiende esto? Definitivamente hay una conversión implícita de String a alguna clase de mezcla en el rasgo SeqLike.

+0

Tricky. Al principio pensé que era porque solo puedes tener uno implícito a la vez, pero ahora parece que también es un problema de varianza escondido en alguna parte ... – Debilski

+2

@Debilski, no estoy seguro de dónde '|>' está definido en scalaz, pero cuando Traté de definir el mío, creo que la "única regla implícita" es lo que impidió su aplicación: "aoeu" necesitaría ser convertido implícitamente a la clase con el método '|>' y luego nuevamente a 'SeqLike'. – huynhjl

+1

Muestra el mensaje de error. No todos tienen Scalaz disponible, pero los mensajes de error generalmente explican lo que está pasando mal. –

Respuesta

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

mensaje El error es bastante claro.

Aunque hay una conversión implícita de String a SeqLike[_,_], no hay conversión (SeqLike[_, _]) => Int-String => ?.

Esto se puede solucionar utilizando la siguiente conversión implícita:

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

Editar 2: aquí es un operador no 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) 

A continuación, puede utilizar de esta manera:

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

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

Permite |%> tomar una función que no funciona directamente sobre una T pero en una X, siempre y cuando no hay evidencia de una implícita conversión de T a X.

2

No utilice tipos existenciales a menos que sea necesario. Rompen cosas, y no se requieren aquí.

Por otro lado, ver en el error en la otra respuesta dejó las cosas más claras. Hay dos conversiones implícitas cuando se usa |>. ¿Funciona si se declara que esta forma:

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

Esto devuelve: 'no se pudo encontrar el valor implícito para el parámetro de evidencia del tipo (CC) => scala.collection.SeqLike [_, _]' – huynhjl