2015-10-18 21 views
1

匿名函數的返回類型:爲什麼我寫下鑑於這種代碼在Scala歌劇院倍

package fpinscala.datastructures 
sealed trait Tree[+A] 
case class Leaf[A](value: A) extends Tree[A] 
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A] 

object Tree { 

    def fold[A,B](t: Tree[A])(f: A => B)(g: (B,B) => B): B = { 
    t match { 
     case Leaf(x) => f(x) 
     case Branch(l,r) => g(fold(l)(f)(g),fold(r)(f)(g)) 
    } 
    } 

    def mapViaFold[A,B](t:Tree[A])(f: A => B): Tree[B] = { 
    fold(t)(a => Leaf(f(a)): Tree[B])(Branch(_,_)) 
    } 

} 

爲什麼我寫下功能a => Leaf(f(a)): Tree[B]的返回類型?沒有它,我得到的錯誤信息:

Error:(54, 36) type mismatch; 
found : fpinscala.datastructures.Branch[B] 
required: fpinscala.datastructures.Leaf[B] 
    fold(t)(a => Leaf(f(a)))(Branch(_,_)) 
           ^
+0

在這裏找到答案:https://github.com/fpinscala/fpinscala/blob/master/answers/src/main/scala/fpinscala/datastructures/Tree.scala#L60 –

回答

1

因爲在摺疊定義的類型參數B在這種情況下,從術語Leaf(f(a))推斷爲Leaf[B]。然後,您的類型與Branch(_,_),(Leaf[B],Leaf[B]) => Branch[B]類型不匹配,這將不會是所需類型(Leaf[B], Leaf[B]) => Leaf[B]的子類型。

UPDATE 我認爲行爲是由於類型重建Scala中是如何工作的:它是基於參數列表(不是單參數),並且它會從左至右。因此,一旦編譯器能夠推斷參數列表的某些類型,它將使用它們來解析右側的參數列表的類型,但不會反過來。

下面我試圖提取形式更簡單的問題:

trait A 
class B extends A 
class C extends A 

def f[T](x: T)(y: T): Int = 1 
def g[T](x: T, y: T): Int = 1 

f(new B)(new C) // Does not compile 
g(new B, new C) // Compiles 

在令行禁止版本,T被推斷爲B第一個參數列表之後,我們在得到那麼一個類型錯誤第二個。

在非緊急版本中,編譯器使用唯一參數列表中的所有參數來推斷T的類型,即在這種情況下最小上限A,正如我們所預期的那樣。

+0

爲什麼編譯器無法解決一個超類型的葉[B]是否滿足這兩個表達式? –

+0

我更新了我認爲是UPDATE部分下的原因的答案。 –