2011-01-15 8 views
13

Ich kann scalaz|> Operator verwenden, wenn ich Funktion und Objekt wechseln möchte, damit es ein wenig mehr Lesbarkeit erworben werden kann. Lassen Sie mich Ihnen eine Modellfunktion vorstellen: Switch-Funktion und Objekt mit Scalaz '|>

def length2(x:String) = x.length * 2
Jetzt kann ich es auf beide Arten schreiben:
"aoeu" |> length2 
length2("aoeu")
Aber wenn ich diese Funktion generischer definiere, hört es auf zu arbeiten.
def length2(x:SeqLike[_,_]) = x.length * 2 
length2("aoeu") // ok 
"aoeu" |> length2 // doesn't work
Warum der Compiler das nicht versteht? Es gibt definitiv eine implizite Umwandlung von String in eine Klasse, die in Merkmal SeqLike mischt.

+0

Tricky. Zuerst dachte ich, es liegt daran, dass man nur einen implizit haben kann, aber jetzt scheint es vielleicht auch ein Varianzproblem irgendwo versteckt zu sein ... – Debilski

+2

@Debilski, ich bin mir nicht sicher, wo '|> 'in scalaz definiert ist, aber wann Ich habe versucht, mein eigenes zu definieren, ich denke, die "einzige implizite Regel" ist es, die das Anwenden verhinderte: "aoeu" müsste implizit in die Klasse mit der '|>' Methode und dann wieder in 'SeqLike' konvertiert werden. – huynhjl

+1

Zeigt die Fehlermeldung an. Nicht jeder hat Scalaz bereitwillig verfügbar, aber Fehlermeldungen erklären normalerweise, was schief läuft. –

Antwort

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

Die Fehlermeldung ist ziemlich klar.

Zwar gibt es eine implizite Konvertierung von String zu SeqLike[_,_], gibt es keine Umwandlung von (SeqLike[_, _]) => Int zu String => ?.

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

Edit 2: hier ist ein nicht-scalaz Operator

Dies kann mit der folgenden impliziten Konvertierung wird festgelegt.

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) 

Dann können Sie es wie folgt verwenden:

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

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

Es ermöglicht |%> eine Funktion zu übernehmen, die nicht direkt auf einem T funktioniert aber auf einem X solange es Anzeichen für eine implizite ist Umwandlung von T zu X.

2

Verwenden Sie keine existentiellen Typen, es sei denn, dies ist erforderlich. Sie brechen Dinge und sind hier nicht erforderlich.

Auf der anderen Seite machte das Sehen in dem Fehler in der anderen Antwort die Dinge klarer. Sie werden aufgefordert, zwei implizite Konvertierungen anzugeben, wenn Sie |> verwenden. Funktioniert es, wenn Sie es wie folgt statt erklären:

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

Dies gibt zurück: 'konnte keinen impliziten Wert für den Beweisparameter des Typs (CC) => scala.collection.SeqLike [_, _]' finden – huynhjl