2017-07-20 3 views
1

Ich implementiere den List-Typ in Scala, wenn Sie ein Buch folgen.Scala übergeben eine generische Funktion in eine andere generische Funktion Verwirrung

Hier ist die Definition meiner Liste Typ:

sealed trait List[+A] 

case object Nil extends List[Nothing] 
case class Cons[+A](head: A, tail: List[A]) extends List[A] 

Alle später genannten Funktionen in der Begleiter Objektliste in der gleichen Datei

object List 

Ich schrieb foldLeft und foldRight wie folgt definiert werden

def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match { 
    case Nil => z 
    case Cons(x, xs) => foldLeft(xs, f(z, x))(f) 
} 

def foldRight[A,B](l: List[A], z: B)(f: (A, B) => B): B = l match { 
    case Nil => z 
    case Cons(x, xs) => f(x, foldRight(xs, z)(f)) 
} 

Es gibt eine Übung auf dem Buch, das foldLeft mit foldRight zu implementieren ist. Hier ist meine erste Implementierung

def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = { 
    foldRight(l, z)((a: A, b: B) => f(b, a)) 
} 

Dann denke ich, dass ich eine andere Funktion schreiben sollte die umgekehrten Argumente zu tun, wenn ich foldRight mit foldLeft implementieren bin. Wie folgt:

def reverseArgs[A,B](f: (A, B) => B): (B, A) => B = { 
    (b: B, a: A) => f(a, b) 
} 

Also änderte ich Code von foldLeftWithRight auf die folgenden:

def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = { 
    foldRight(l, z)(reverseArgs(f)) 
} 

Und IntelliJ beschwert sich über reverseArgs(f):

Typenkonflikt: erwartet (A, B) = > B, Ist (B, B) => B

Wenn ich es versuche den Code zu kompilieren, ist der Fehler der folgende:

Error:(21, 37) type mismatch; 
    found : (B, A) => B 
    required: (B, Any) => Any 
     foldRight(l, z)(reverseArgs(f)) 

Eine interessante Beobachtung ist, dass, wenn ich die reverseArgs auf foldRightWithLeft verwenden, gibt es kein Problem:

def foldRightWithLeft[A,B](l: List[A], z: B)(f: (A, B) => B): B = { 
    foldLeft(l, z)(reverseArgs(f)) 
} 

Was ist hier los?

Antwort

2

Wenn Sie Typ Parameter Ihrer reverseArgs Funktion X und Y umbenennen, werden Sie so etwas wie

def reverseArgs[X ,Y](f: (X, Y) => Y): (Y, X) => Y = ??? 

Typ f in foldLeftWithRight bekommen ist (B, A) => B. dass reverseArgs Passing bedeutet:

X = B 
Y = A 
Y = B 

Ich denke, IntelliJ hier aus, dass A = B folgert, und das ist, warum es sich beschwert, dass (B, B) => B nicht (A, B) => B. Scalac entscheidet stattdessen, dass Y = Any ist, weil es die kleinste Obergrenze von zwei potenziell nicht verwandten Typen ist.


Gute Lösung hier ist, mehr zu verallgemeinern.Der Rückgabetyp der umgekehrten Funktion muss nicht einer der Parametertypen sein. Sie können also einen anderen generischen Typ eingeben:

def reverseArgs[X ,Y, Z](f: (X, Y) => Z): (Y, X) => Z = { 
    (b: Y, a: X) => f(a, b) 
} 
+0

Jetzt macht das Sinn, danke! – KenKenKen

Verwandte Themen