2017-01-11 2 views
1

Ich versuche, eine generische Bibliothek für Haskell zu Scala zu portieren. Allerdings bin ich momentan nicht wirklich glücklich darüber, wie ich die generische Crush-Funktion in Scala gelöst habe.Scala Mehrere Typparameter, die später definiert werden

Ich definierte zu folgenden behandelt, um Crush-Funktionen zu behandeln.

Als nächstes wollte ich die Quetschfunktion definieren, aber hier stieß ich auf Probleme. Das Problem ist, dass ich diese FRep-Eigenschaft brauche, um die Crush-Funktion darzustellen, aber das G (Generic) in frep erlaubt nur 1 Parameter. Ich habe das mit Lambdatypen gelöst, aber ich habe immer noch Probleme, eine Funktion zu definieren. Dies ist der Ansatz, den ich arbeiten wollte:

def crush[B,A,F[_]](asc : Assoc)(f : A => B => B)(z : B)(x : F[A])(implicit rep : FRep[({type AB[A] = Crush[B,A]})#AB,F]): B = { 
    def fCrush = new Crush[B,A]{ 
     override def selCrush= _ => f 
    } 
    return(rep frep(fCrush).selCrush(asc)(x)(z)) 
} 

Diese offensichtlich einen Fehler gab, weil die A-Parameter in der Crush-Funktion nicht das gleiche wie die Ein Lambda-Typ in dem impliziten rep Variable ist, das gleiche sein muss um die Crush-Funktion zu verwenden. Dies ist der Fehler, den ich erhalten:

<pastie>:677: error: type mismatch; 
found : x.type (with underlying type F[A]) 
required: A 
     return(rep frep(fCrush).selCrush(asc)(x)(z)) 

Also, die Lösung kam ich mit ist die Crush-Funktion in mehrere Teile aufgeteilt, so dass ich die gleiche A für die Crush-Funktion verwenden können. Dies ist die aktuelle Lösung, die kompiliert:

class CrushFunction[B,F[_]](asc : Assoc)(z : B)(implicit rep : FRep[({type AB[A] = Crush[B,A]})#AB,F]){ 
    def crush[A](f : A => B => B)(x : F[A]) : B = { 
     val crushVal = new Crush[B,A]{ 
      override def selCrush: Assoc => A => B => B = _ => f 
     } 
     return(rep.frep(crushVal).selCrush(asc)(x)(z)) 
    } 
} 

Also, meine Frage ist: Gibt es eine schönere Art und Weise, diese zu lösen?

Antwort

2

Eigentlich ist das einzige Problem mit Ihrer ersten Lösung, dass Sie den Punkt zwischen rep und frep weggelassen haben. Ich würde auch empfehlen Ihnen nicht return explizit zu verwenden, und keine Namen von Typparametern beschatten (A):

def crush[B,A,F[_]](asc : Assoc)(f : A => B => B)(z : B)(x : F[A])(implicit rep : FRep[({type AB[X] = Crush[B,X]})#AB,F]): B = { 
    def fCrush = new Crush[B,A]{ 
     override def selCrush: Assoc => A => B => B = _ => f 
    } 
    rep.frep(fCrush).selCrush(asc)(x)(z) 
} 

Jetzt können Sie sich fragen: warum diese Fehlermeldung, wenn alles, was falsch ist ein fehlender Punkt ist? Nun, Scala unterstützt Infix-Notation. Es analysiert a b c d e als a.b(c).d(e). Aber du hast so etwas geschrieben: a b(c).d(e). Dies verwirrt den Parser. Sie können sehen, was passiert, wenn Sie //print an Ihren Code in der REPL (Version 2.11.8 oder höher denke ich) anfügen und die TAB-Taste drücken.

Ich filterte den ganzen Zoll für Sie aus. rep frep(fCrush).selCrush(asc)(x)(z) wie analysiert wird:

rep.frep[A](fCrush.selCrush(asc)(x)(z)) 

In diesem Ausdruck x ist in der Tat A statt F[A] als Typ erforderlich.

Ehrlich gesagt: für mich scheint es ein bisschen wie ein Fehler, dass scalac es geschafft hat, Ihren dotless Code zu analysieren, eine Klammer dabei völlig ignorierend. Nennen wir es eine unglückliche Syntax-Eigenart :-)

+0

-Xlint für schattierten Typ param. Wie würdest du "Hallo" + ("Welt"). Länge "parsen? Ich denke, dass sie eine Annotation hinzufügen möchten, um anzuzeigen, welche Mitglieder (Operatoren) unbestimmt verwendet werden können. Das soll der Lesbarkeit dienen, aber vielleicht könnte eine Abid-Regel vor alnum infix warnen, gefolgt von Leerzeichen (etc). –

+0

Sie haben Recht. Das funktioniert! Danke für die tolle Erklärung! – maffh

Verwandte Themen