嗯,你可以,
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) 并统一来自 foldLeft 示例调用的签名中的类型:
List[T] : List[Int],因此 T : Int 和 R : List[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 的类型统一起来:
a : List[Int] 和 b : Int,与a2 :: b2 的签名比较,a2 : Int, b2 : 列表[Int]。为了编译,a 和 a2 以及 b 和 b2 必须各自具有相同的类型。他们没有!
请注意,在我的示例中,我反转了参数,使 a 匹配 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 的参数是相反的,它首先使用函数和初始参数,签名中的r,而不是:: 用于列表构造,它只使用:。两个非常小的细节。