вывод типа все еще нуждается в улучшении, есть ли лучшее предложение для этого примера? - PullRequest
4 голосов
/ 24 мая 2010

, например, в 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, а затем выполнить ошибку.Может ли какое-либо более интуитивное кодирование, как Clojure выше?

Ответы [ 5 ]

4 голосов
/ 24 мая 2010

Вот вам отдельные списки:

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

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

Вычисляемая наименьшая верхняя граница (LUB) Double и Int, необходимая для захвата типа нового списка, который включает элементы обоихсписки аргументов, переданные в :::, это AnyVal.AnyVal включает Boolean, например, поэтому числовые операции не определены.

2 голосов
/ 24 мая 2010

Как уже сказал Рэндалл, общим супертипом 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.Однако я не уверен, почему он не применяется при добавлении параметра типа в первый список.

1 голос
/ 24 мая 2010

Первый список имеет тип List[Double] из-за расширения литерального типа. Скала видит литералы и отмечает, что, хотя они бывают разных типов, их можно объединить, расширив некоторые из них. Если бы не было расширения типа, то был бы принят самый распространенный суперкласс, AnyVal.

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

Второй список явно List[Int], хотя явный вызов Double приведет к расширению типа для литералов.

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

Теперь важно отметить, что расширение типов - это то, что происходит во время compile . Скомпилированный код не будет содержать Int 3, только Double 3.0. Однако после создания списка расширение типов становится невозможным, поскольку хранимые объекты на самом деле разные.

Итак, после того, как вы объедините два списка, результирующий тип будет суперклассом Double и Int. А именно, AnyVal. Однако в результате взаимодействия Java AnyVal не может содержать никаких полезных методов (таких как числовые операторы).

Мне интересно, что делает Clojure внутри. Преобразует ли это целые числа в двойники при конкатенации? Или он хранит все как Object (как это делает Scala), но имеет более умные математические операторы?

0 голосов
/ 25 мая 2010

Почему бы просто,

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

?

0 голосов
/ 25 мая 2010

Я вижу два способа заставить это работать - фигурные скобки для второй части

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)

, что, конечно, семантически отличается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...