1 ::在foldLeft中列出[Nothing]

ses*_*ses 7 generics haskell scala

如果:

scala> val l = List()      // List() same as List[Nothing]()
l: List[Nothing] = List()

scala> 1 :: l
res0: List[Int] = List(1)
Run Code Online (Sandbox Code Playgroud)

要么:

scala> 1 :: List[Nothing]()
res6: List[Int] = List(1)
Run Code Online (Sandbox Code Playgroud)

为什么然后这没有成功:

scala> List(1,2,3). foldLeft( List() ) ((acc,x) => x :: acc)
Run Code Online (Sandbox Code Playgroud)

所以我必须明确键入List[Int]():

scala> List(1,2,3). foldLeft( List[Int]() ) ((acc,x) => x :: acc)
res3: List[Int] = List(3, 2, 1)
Run Code Online (Sandbox Code Playgroud)

虽然它在Haskell中确实存在,例如:

 foldl (\acc x -> x:acc) [] [1,2,3]
Run Code Online (Sandbox Code Playgroud)

dk1*_*k14 9

让我们来看看scala的foldLeft签名:

List[+A].foldLeft[B](z: B)(f: (B, A) ? B): B
Run Code Online (Sandbox Code Playgroud)

和哈斯克尔的签名:

foldl :: (b -> a -> b) -> b -> [a] -> b
Run Code Online (Sandbox Code Playgroud)

他们几乎一样,但是:

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)
                         ^
Run Code Online (Sandbox Code Playgroud)

因此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)
Run Code Online (Sandbox Code Playgroud)

在这里,scala不仅选择了更大的类型 - 它已经找到了两者的共同超类型T.因此,默认情况下,它试图选择更大的类型(如果它在左侧部分),但在一个参数列表中查找常见的超类型.

注意:我在谈论[伪] currying,因为多个参数列表的方法(B)((B, A) => B)B只有在eta-expansion之后变成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"]
Run Code Online (Sandbox Code Playgroud)

在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)
Run Code Online (Sandbox Code Playgroud)

3)最后,让我们重写foldLeft并将monoid的'add'和'identity'放在同一参数列表中(以避免与p.1分开推断):

 def foldLeft[T, U](l: List[T])(identity: U, add: (U,T) => U) = l.foldLeft(identity)(add)
Run Code Online (Sandbox Code Playgroud)

并定义多态add操作:

 scala> def add[A](x: List[A], y: A) = y :: x
 add: [A](x: List[A], y: A)List[A]
Run Code Online (Sandbox Code Playgroud)

所以你可以:

scala> foldLeft(List(1,2,3))(Nil, add)
res63: List[Int] = List(3, 2, 1)
Run Code Online (Sandbox Code Playgroud)

与以下比较:

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)
                                    ^
Run Code Online (Sandbox Code Playgroud)

不幸的是,scala无法推断lambda的泛型类型,所以你不能:

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)
Run Code Online (Sandbox Code Playgroud)

你不能:

scala> val a = (acc,x) => x :: acc
<console>:7: error: missing parameter type
   val a = (acc,x) => x :: acc
            ^
Run Code Online (Sandbox Code Playgroud)

2&3)因为scala根本没有多态lambda.无法A => List[A] => A(acc,x) => x :: acc(甚至A => A来自val a = (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]
Run Code Online (Sandbox Code Playgroud)

这是addscala 中以前定义的泛型方法的eta扩展:

scala> add _
res2: (List[Nothing], Nothing) => List[Nothing] = <function2>
Run Code Online (Sandbox Code Playgroud)