1 ::列出foldLeft中的[Nothing] [英] 1 :: List[Nothing] in foldLeft

查看:78
本文介绍了1 ::列出foldLeft中的[Nothing]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果:

  scala> val l = List()// List()与List相同[Nothing]()
l:List [Nothing] = List()

scala> 1 :: l
res0:List [Int] = List(1)

或者:

  scala> 1 :: List [Nothing]()
res6:List [Int] = List(1)

为什么然后这不起作用:

  scala>列表(1,2,3)。 foldLeft(List())((acc,x)=> x :: acc)

我必须明确输入 List [Int]()

 阶>列表(1,2,3)。 foldLeft(List [Int]())((acc,x)=> x :: acc)
res3:List [Int] = List(3,2,1)




尽管它在Haskell中有效,例如:


$ b $

  foldl(\acc x  - > x:acc)[] [1,2,3] 

解决方案

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

 列表[+ 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)单位

scala> aaa(null:任何)(5)

scala> aaa(5)(null:Any)
< console>:21:error:type mismatch;
找到:任何
都需要:Int
aaa(5)(null:Any)
^

所以scala可以从左到右选择更大的类型。 更重要的是,这只是[pseudo - ] 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 的s。所以,它试图在默认情况下选择更大的类型(如果它在左边部分),但是在一个参数列表中寻找一个常见的超类型。



注意:我是谈论[pseudo-] currying,作为具有多个参数列表的方法(B)((B,A)=> B)B 仅在eta-expansion之后变为curried函数: foldLeft _ 给出 B => (B,A)=> 2)haskell使用 List的作为函数的参数,它甚至可以让你做到:

  Prelude>让f = foldl(\acc x  - > x:acc)[] 
:: [a] - > [a] //这里是多态函数
Prelude> f [1,2,3]
[3,2,1]
前奏> f [1,2,3]
[3,2,1]

在scala中你需要:

  scala> (x,f)= x :: acc)
f:[T](x:列表[T])列表[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)
foldLeft ,并将monoid的'add'和'identity'放在同一个参数列表中(避免与p.1分开推论):

pre $ def foldLeft [T,U](l:List [T]) (身份: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]

所以您可以:

 阶> foldLeft(List(1,2,3))(Nil,add)
res63:List [Int] = List(3,2,1)

$ b

与以下比较:

  scala> List(1,2,3).foldLeft(Nil)(add)
< console>:9:error:多态表达式不能实例化为预期类型;
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不能推断lambda表达式的泛型类型,所以你不能:

 阶> foldLeft(List(1,2,3))(Nil,(acc,x)=> x :: acc)
< console>:10:error:缺少参数类型
foldLeft(List (1,2,3))(Nil,(acc,x)=> x :: acc)

您无法:

  scala> val a =(acc,x)=> x :: acc 
< console>:7:错误:缺少参数类型
val a =(acc,x)=> x :: acc
^



<2>& 3)因为scala完全没有多态lambda 。无法推断 A =>列表[A] =>从(acc,x)=>的一个(其中A是一个类型参数) x :: acc (甚至 A => A from val a =(a)=> a ),但Haskell可以:

  Prelude> let lambda = \acc x  - > x:acc 
:: [a] - > a - > [a]
前奏>让f = foldl(lambda)[]
Prelude> f [1,2,3]
[3,2,1]

这里是在scala中定义了 add 泛型方法的eta-expansion:

 阶>添加_ 
res2:(List [Nothing],Nothing)=> List [Nothing] =< function2>


If:

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

scala> 1 :: l
res0: List[Int] = List(1)

or:

scala> 1 :: List[Nothing]()
res6: List[Int] = List(1)

Why then this does not work out:

scala> List(1,2,3). foldLeft( List() ) ((acc,x) => x :: acc)

So I have to type this explicitly List[Int]():

scala> List(1,2,3). foldLeft( List[Int]() ) ((acc,x) => x :: acc)
res3: List[Int] = List(3, 2, 1)

?

Though it does in Haskell, for example:

 foldl (\acc x -> x:acc) [] [1,2,3]

解决方案

Let's look at scala's foldLeft signature:

List[+A].foldLeft[B](z: B)(f: (B, A) ⇒ B): B

and haskell's signature:

foldl :: (b -> a -> b) -> b -> [a] -> b

They pretty much same, but:

1) scala has problem with type inference between [pseudo-]curried parameter lists, just compare:

 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)
                         ^

So scala can choose bigger type from left to right only.

More than that, this is a problem only for [pseudo-]curried functions:

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)

Here scala had not only choosed a bigger type - it had found a common supertype of both T's. So, it's trying to choose bigger type (if it's in the left part) by default, but looking for a common supertype inside one parameter list.

Note: I'm talking about [pseudo-] currying, as method with multiple parameter lists (B)((B, A) => B)B becoming curried function only after eta-expansion: foldLeft _ gives B => (B,A) => B

2) haskell uses "object" of List itself as function's parameter, which allows you to do even:

 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"]

In scala you need:

 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) Finally, let's rewrite foldLeft and place monoid's 'add' and 'identity' to the same parameter list (to avoid separate inference from p.1):

 def foldLeft[T, U](l: List[T])(identity: U, add: (U,T) => U) = l.foldLeft(identity)(add)

and define polymorphic add operation:

 scala> def add[A](x: List[A], y: A) = y :: x
 add: [A](x: List[A], y: A)List[A]

So you can:

scala> foldLeft(List(1,2,3))(Nil, add)
res63: List[Int] = List(3, 2, 1)

in comparision with:

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)
                                    ^

Unfortunately, scala can't infer generic type for lambdas, so you can't:

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)

as you can't:

scala> val a = (acc,x) => x :: acc
<console>:7: error: missing parameter type
   val a = (acc,x) => x :: acc
            ^

2 & 3) Because scala has no polymorphic lambdas at all. Can't infer A => List[A] => A (where A is a type parameter) from (acc,x) => x :: acc (even A => A from val a = (a) => a), but Haskell can:

Prelude> let lambda = \acc x -> x:acc
:: [a] -> a -> [a]
Prelude> let f = foldl(lambda) []
Prelude> f [1,2,3]
[3,2,1]

Here is an eta-expansion of perviously defined add generic method in scala:

scala> add _
res2: (List[Nothing], Nothing) => List[Nothing] = <function2>

这篇关于1 ::列出foldLeft中的[Nothing]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆