foldRight和foldLeft之间的区别,为什么我不能使用倍以下代码左图:什么的Concat
def concatList[T](xs: List[T],ys:List[T]): List[T]=
(xs foldLeft ys)(_::_)
其实这是我很难理解foldRight和foldLeft之间的区别,它有什么例子来说明真正的差异?
谢谢。
foldRight和foldLeft之间的区别,为什么我不能使用倍以下代码左图:什么的Concat
def concatList[T](xs: List[T],ys:List[T]): List[T]=
(xs foldLeft ys)(_::_)
其实这是我很难理解foldRight和foldLeft之间的区别,它有什么例子来说明真正的差异?
谢谢。
好了,就可以了,
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,在特殊这两不可想象的:
通知,与foldl参数和foldr相似反转时,它首先需要的功能和它们的inital参数,r
在签名,而不是::
列表建设,它只使用:
。两个非常小的细节。
一个从左到右,另一个从右到左。 – Reactormonk