类型推断还需要增强,对这个例子有什么更好的建议吗?

时间:2010-05-24 13:31:34

标签: scala clojure

例如在Clojure中:

user=> (map #(* % 2) (concat [1.1 3] [5 7]))

(2.2 6 10 14)

但是在Scala:

scala> List(1.1,3) ::: List(5, 7) map (_ * 2)

<console>:6: error: value * is not a member of AnyVal
       List(1.1,3) ::: List(5, 7) map (_ * 2)
                                       ^

这里:::获取List类型列表,然后oops失败。任何编码都能比上面的Clojure更直观吗?

5 个答案:

答案 0 :(得分:4)

以下是您的个人名单:

scala> List(1.1,3)
res1: List[Double] = List(1.1, 3.0)

scala> List(5, 7)
res2: List[Int] = List(5, 7)

DoubleInt的计算最小上限(LUB),用于捕获包含传递给:::的两个参数列表的元素的新列表的类型, AnyValAnyVal包括Boolean,例如,因此没有定义数字操作。

答案 1 :(得分:2)

正如Randall已经说过的,Double和Int的常见超类型是AnyVal,在这种情况下推断出来。我可以让你的例子工作的唯一方法是在第二个列表中添加一个类型参数:


scala> List[Double](1.1,3) ::: List(5, 7) map (_ * 2)
:6: error: value * is not a member of AnyVal
       List[Double](1.1,3) ::: List(5, 7) map (_ * 2)

scala> List(1.1,3) ::: List[Double](5, 7) map (_ * 2)
res: List[Double] = List(2.2, 6.0, 10.0, 14.0)

我想在后一种情况下,应用从Int到Double的隐式转换。但是,我不确定为什么在将类型参数添加到第一个列表时没有应用它。

答案 2 :(得分:1)

由于文字类型加宽,第一个列表的类型为List[Double]。 Scala看到了文字,并指出,即使它们属于不同的类型,它们也可以通过扩大其中的一些来统一。如果没有类型扩展,那么将采用最常见的超类AnyVal

List(1.1 /* Double literal */), 3 /* Int literal */)

第二个列表显然是List[Int],但显式调用Double会导致文字类型扩大。

List(5 /* Int literal */, 7 /* Int literal */)

现在,重要的是要注意类型扩展是在编译时发生的事情。编译后的代码不包含任何Int 3,仅包含Double 3.0。但是,一旦列表被创建,就不可能进行类型扩展,因为存储的对象实际上是不同的。

因此,一旦您连接两个列表,结果类型将是DoubleInt的超类。即,AnyVal。但是,由于Java互操作性,AnyVal不能包含任何有用的方法(例如数字运算符)。

我确实想知道Clojure在内部做了什么。连接时是否将整数转换为双精度?或者它将所有内容存储为Object(与Scala一样),但是有更聪明的数学运算符吗?

答案 3 :(得分:0)

我认为有两种方法可以使它发挥作用 - 第二部分的支撑

scala> List (1.1, 3) ::: (List (5, 7) map (_ * 2))
res6: List[AnyVal] = List(1.1, 3, 10, 14)
到处都是明显的双打:

scala> List (1.1, 3.) ::: List (5., 7.) map (_ * 2)  
res9: List[Double] = List(2.2, 6.0, 10.0, 14.0)

当然在语义上是不同的。

答案 4 :(得分:0)

为什么不呢,

(List(1.1,3) ::: List(5, 7)).asInstanceOf[List[Double]] map (_ * 2)