2017-07-20 22 views
1

我正在Scala中實現List類型,當遵循一本書時。Scala將通用函數傳遞到另一個泛型函數混淆

這裏是我的列表類型的定義:

sealed trait List[+A] 

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

所有後述的功能在同伴對象列表定義在同一個文件

object List 

我寫foldLeftfoldRight爲以下

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)) 
} 

有一個exerci這本書是用foldRight實施foldLeft。這是我的初步實施

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

然後我覺得我應該寫另一個函數做相反的論點,如果我使用foldLeft實現foldRight。如下:

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

因此,我改變的foldLeftWithRight代碼爲以下:

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

和IntelliJ抱怨reverseArgs(f)

類型不匹配:預期(A,B)= > B,actual(B,B)=> B

當我嘗試編譯代碼,錯誤是:

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

一個有趣的現象是,當我使用foldRightWithLeftreverseArgs,有沒有問題:

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

這到底是怎麼回事?

回答

2

如果重命名reverseArgs功能XY的類型參數,你會得到這樣的

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

f鍵入foldLeftWithRight(B, A) => B。順便指出,以reverseArgs意味着:

X = B 
Y = A 
Y = B 

我猜的IntelliJ從這裏A = B推斷,這就是爲什麼它抱怨(B, B) => B(A, B) => B。 Scalac決定Y = Any,因爲它是兩個可能無關的類型的最小上界。


好的解決辦法是推廣更多。返回類型的反轉函數不一定是參數類型之一,因此您可以爲此引入另一個通用類型:

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

現在,這是有道理的,謝謝! – KenKenKen

相關問題