2016-11-11 15 views
1

foldRight和foldLeft之间的区别,为什么我不能使用倍以下代码左图:什么的Concat

def concatList[T](xs: List[T],ys:List[T]): List[T]= 
    (xs foldLeft ys)(_::_) 

其实这是我很难理解foldRight和foldLeft之间的区别,它有什么例子来说明真正的差异?

谢谢。

+1

一个从左到右,另一个从右到左。 – Reactormonk

回答

5

好了,就可以了,

scala> def concatList[T](xs: List[T],ys:List[T]) = 
     (xs foldLeft ys)((a, b) => b :: a) 
concatList: [T](xs: List[T], ys: List[T])List[T] 

scala> concatList(List(1,2,3), List(6,7,8)) 
res0: List[Int] = List(3, 2, 1, 6, 7, 8) 

是,结果你期待?我不这么认为。

首先,让我们看看褶皱和::的签名(仅用于说明目的的简化,但是对我们来说非常适合):

given a List[T] 
    def ::(v:T): List[T] // This is a right associative method, more below 
    def foldLeft[R](r:R)(f: (R,T) => R):R 
    def foldRight[R](r:R)(f: (T,R) => R):R 

现在,foldLeft申请一个参数列表我们xs.foldLeft(ys)和统一

列表[T]:从我们从foldLeft样品呼叫签名类型列表[INT],因此T:诠释,和R:列表[INT],使得施加到foldLeft签名给出

foldLeft[List[Int]](r:List[Int])(f:(List[Int],Int) => List[Int]) 

现在,对于的::用法,a :: b编译为b.::(a),Scala中经常是指它作为一个右结合方法。这是一个以:结尾的方法的特殊语法糖,并且在定义列表时非常方便:1 :: 2 :: Nil就像是写作Nil.::(2).::(1)

继续我们实例化foldLeft,我们需要传递的函数看起来像这样:(List[Int],Int) => List[Int]。考虑(a,b) => a :: b,如果我们结合,与我们的类型f得到:

一个:列表[INT]B:诠释,比较,随着a2 :: b2签名,A2:诠释b2:列表[Int]。为了编译,a和a2与b和b2一起必须具有相同的类型。他们不这样做!

请注意,在我的例子中,我倒过来的参数,使匹配类型的b2和b匹配类型的a2。

我将提供又可以编译另一个版本:

def concatList[T](xs: List[T],ys:List[T]) = (xs foldLeft ys)(_.::(_)) 

为了削减长话短说,看foldRight签名

def foldRight[R](r:R)(f: (T,R) => R):R 

的参数已经反转,所以使得f = _ :: _给我们的权利类型。

哇,这是关于类型推断的很多解释,我按时排序,但我仍然欠缺解释左右折叠含义的区别。现在看看https://wiki.haskell.org/Fold,在特殊这两不可想象的:

foldLeft foldRight

通知,与foldl参数和foldr相似反转时,它首先需要的功能和它们的inital参数,r在签名,而不是::列表建设,它只使用:。两个非常小的细节。

相关问题