2011-01-15 14 views
13

Mogę użyć operatora scalaz|>, gdy chcę zmienić funkcję i obiekt, aby uzyskać nieco większą czytelność. Pozwól, że przedstawię ci funkcję modelu: Funkcja przełącznika i obiekt z scalazem | |>

def length2(x:String) = x.length * 2
Teraz mogę napisać to na dwa sposoby:
"aoeu" |> length2 
length2("aoeu")
Ale jeśli zdefiniuję tę funkcję jako bardziej ogólną, przestanie działać.
def length2(x:SeqLike[_,_]) = x.length * 2 
length2("aoeu") // ok 
"aoeu" |> length2 // doesn't work
Dlaczego kompilator tego nie rozumie? Istnieje pewna niejawna konwersja z String na niektóre klasy mieszające w cechach SeqLike.

+0

Tricky. Na początku myślałem, że to dlatego, że możesz mieć tylko jedno niejawne w tym samym czasie, ale teraz wydaje się, że może jest to również problem wariancji ukryty gdzieś ... – Debilski

+2

@Debilski, nie jestem pewien gdzie '|>' jest zdefiniowany w skalazie, ale kiedy Próbowałem zdefiniować własną, myślę, że "tylko jedna niejawna reguła" uniemożliwiła jej zastosowanie: "aoeu" musiałaby zostać niejawnie przekonwertowana na klasę za pomocą metody "|>", a następnie ponownie na "SeqLike". – huynhjl

+1

Wyświetl komunikat o błędzie. Nie wszyscy mają Scalaza łatwo dostępne, ale komunikaty o błędach zwykle wyjaśniają, co się dzieje. –

Odpowiedz

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

komunikat Błąd jest całkiem jasne.

Chociaż istnieje niejawna konwersja z String na SeqLike[_,_], nie ma konwersji z (SeqLike[_, _]) => Int na String => ?.

ten można rozwiązać w następujący niejawna konwersja:

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

Edycja 2: oto operator nie 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) 

Wtedy można go używać tak:

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

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

Pozwala |%> podjąć funkcję, która nie działa bezpośrednio na T ale na X tak długo jak istnieją dowody niejawna konwersja z T na X.

2

Nie wolno używać typów egzystencjalnych, chyba że jest to konieczne. Łamią rzeczy i nie są tu wymagane.

Z drugiej strony, widząc błąd w drugiej odpowiedzi, wszystko stało się bardziej jasne. Podczas korzystania z |> są wymagane dwie niejawne konwersje. To działa, jeśli deklarują to tak zamiast:

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

To zwraca: 'nie można znaleźć wartości domyślnej dla parametru dowodu typu (CC) => scala.collection.SeqLike [_, _]' – huynhjl

Powiązane problemy