如果:
scala> val l = List() // List() same as List[Nothing]()
l: List[Nothing] = List()
scala> 1 :: l
res0: List[Int] = List(1)
或:
scala> 1 :: List[Nothing]()
res6: List[Int] = List(1)
为什么然后这不起作用:
scala> List(1,2,3). foldLeft( List() ) ((acc,x) => x :: acc)
所以我必须明确键入List[Int]()
:
scala> List(1,2,3). foldLeft( List[Int]() ) ((acc,x) => x :: acc)
res3: List[Int] = List(3, 2, 1)
虽然它在Haskell中确实存在,例如:
foldl (\acc x -> x:acc) [] [1,2,3]
答案 0 :(得分:9)
让我们看看scala的foldLeft签名:
List[+A].foldLeft[B](z: B)(f: (B, A) ⇒ B): B
和haskell的签名:
foldl :: (b -> a -> b) -> b -> [a] -> b
他们几乎一样,但是:
1)scala在[伪] curried参数列表之间的类型推断存在问题,只需比较:
scala> def aaa[A](a: A)(b: A) = {}
aaa: [A](a: A)(b: A)Unit
scala> aaa(null: Any)(5)
scala> aaa(5)(null: Any)
<console>:21: error: type mismatch;
found : Any
required: Int
aaa(5)(null: Any)
^
因此scala只能从左到右选择更大的类型。
不仅如此,这只是[伪] curried函数的问题:
scala> def aaa[T](a: T, b: T) = a
aaa: [T](a: T, b: T)T
scala> aaa(List("a"), List(6.0))
res26: List[Any] = List(a)
scala> aaa(List(6.0), List("a"))
res27: List[Any] = List(6.0)
在这里,scala不仅选择了更大的类型 - 它已经找到了T
的两种常见超类型。因此,默认情况下它会尝试选择更大的类型(如果它在左侧部分),但在一个参数列表中寻找一个常见的超类型。
注意:我在谈论[伪] currying,因为只有在eta-expansion之后,多个参数列表(B)((B, A) => B)B
成为curry函数的方法:foldLeft _
给出B => (B,A) => B
2)haskell使用List
本身的“对象”作为函数的参数,这样你就可以做到:
Prelude> let f = foldl (\acc x -> x:acc) []
:: [a] -> [a] //here is the polymorphic function
Prelude> f [1,2,3]
[3,2,1]
Prelude> f ["1","2","3"]
["3","2","1"]
在scala中你需要:
scala> def f[T](x: List[T]) = x.foldLeft(List[T]()) ((acc,x) => x :: acc)
f: [T](x: List[T])List[T]
scala> f(List(1,2,3))
res3: List[Int] = List(3, 2, 1)
scala> f(List("1","2","3"))
res3: List[String] = List(3, 2, 1)
3)最后,让我们重写foldLeft
并将monoid的'add'和'identity'放在同一参数列表中(以避免与p.1分开推断):
def foldLeft[T, U](l: List[T])(identity: U, add: (U,T) => U) = l.foldLeft(identity)(add)
并定义多态add
操作:
scala> def add[A](x: List[A], y: A) = y :: x
add: [A](x: List[A], y: A)List[A]
所以你可以:
scala> foldLeft(List(1,2,3))(Nil, add)
res63: List[Int] = List(3, 2, 1)
与之比较:
scala> List(1,2,3).foldLeft(Nil)(add)
<console>:9: error: polymorphic expression cannot be instantiated to expected type;
found : [A, B](x: List[A], y: A)List[A]
required: (scala.collection.immutable.Nil.type, Int) => scala.collection.immutable.Nil.type
List(1,2,3).foldLeft(Nil)(add)
^
不幸的是,scala无法推断lambdas的泛型类型,所以你不能:
scala> foldLeft(List(1,2,3))(Nil, (acc,x) => x :: acc)
<console>:10: error: missing parameter type
foldLeft(List(1,2,3))(Nil, (acc,x) => x :: acc)
你不能:
scala> val a = (acc,x) => x :: acc
<console>:7: error: missing parameter type
val a = (acc,x) => x :: acc
^
2&amp; 3)因为scala完全没有没有多态lambda 。无法推断A => List[A] => A
(其中A是类型参数)来自(acc,x) => x :: acc
(A => A
来自val a = (a) => a
),但Haskell可以:
Prelude> let lambda = \acc x -> x:acc
:: [a] -> a -> [a]
Prelude> let f = foldl(lambda) []
Prelude> f [1,2,3]
[3,2,1]
以下是scala中以前定义的add
泛型方法的eta扩展:
scala> add _
res2: (List[Nothing], Nothing) => List[Nothing] = <function2>
答案 1 :(得分:3)
def foldLeft[B](z: B)(f: (B, A) => B): B
Nothing
是所有其他类型的子类型,在本例中为Int
。由于List()
被推断为类型为List[Nothing]
,因此f
应为(List[Nothing], A) => List[Nothing]
但在函数(acc, x) => x :: acc)
中,A
是Int
,这意味着您应该:{/ p>
(List[Nothing], Int) => List[Nothing]
当你真的有:
(List[Nothing], Int) => List[Int]
因此类型不匹配,因为List[Int]
不能成为List[Nothing]
。
这类似于:
class A
class B extends A
scala> List.fill(5)(new A).foldLeft(List.empty[B])((acc, x) => x :: acc)
<console>:10: error: type mismatch;
found : A
required: B
List.fill(5)(new A).foldLeft(List.empty[B])((acc, x) => x :: acc)
^