2013-10-15 1 views
1

С канонической «Программирование в Scala» от Oderskey и Веннерсом:Почему isiomatic scala является явным/подробным о некоторых [x [/ Option [x]?

scala> val results = List(Some("apple"), None, 
        Some("orange")) 
     results: List[Option[java.lang.String]] = List(Some(apple), 
     None, Some(orange)) 
     scala> for (Some(fruit) <- results) println(fruit) 
     apple 
     orange 

Я не понимаю философию Скале навязать программисту необходимость явно указать некоторые (яблоко), в отличие от выводя его. Я бы предпочел, чтобы писать/увидеть следующее:

scala> val results = List("apple", None, "orange") 
     results: List[Option[java.lang.String]] = List(apple, None, orange) 
     scala> for (fruit <- results) println(fruit) 
     apple 
     orange 

Или, может быть, по крайней мере следующее (при условии, набрав на уровне списка, но не на уровне отдельного элемента):

scala> val results :List[Option[String]] = ("apple", None, "orange") 
     results: List[Option[java.lang.String]] = List(apple, None, orange) 
     scala> for (fruit <- results) println(fruit) 
     apple 
     orange 

По крайней мере, в этот последний случай: тип List предоставляется (чтобы помочь компилятору ..), но мы все же избегаем многословия «бокса» каждого элемента в списке, например Some («foo»).

Любой, кто лучше настроился на способ мышления Scala, может сказать мне, почему мне нужно делать это, чтобы набрать еще ...?

Редактировать: так что делает то, что я хочу для строк.

scala> implicit def toOpt(a : String) = Some(a) 
toOpt: (a: String)Some[String] 

scala> val myList : List[Option[String]] = List("first", None, "third") 
myList: List[Option[String]] = List(Some(first), None, Some(third)) 

Если кто-то может показать, как обобщить приведенное выше, используя более высокие типы типов, я дам вам ответ.

+0

Вы могли бы write 'for (fruit <- results.flatten) println (fruit)', если вам не нравится деконструкция шаблона. –

+0

Моя «говядина» не с разложением рисунка, а с некоторыми («яблоко»), «Некоторые» («оранжевые») и т. Д. – javadba

+0

Является ли результат «val»: List [Option [String]] = ... 'действительно что гораздо менее многословно? Я подозреваю, что язык был разработан в соответствии с этими строками, вам нужно было бы дать компилятору гораздо больше типов подсказок, чем сейчас. – Shadowlands

ответ

2

Я не одобряю это, но то, что вы, кажется, ищете это:

scala> implicit def aToOptionA[T](a:T):Option[T]=Some(a) 
warning: there were 1 feature warning(s); re-run with -feature for details 
aToOptionA: [T](a: T)Option[T] 

scala> val myList : List[Option[String]] = List("first", None, "third") 
myList: List[Option[String]] = List(Some(first), None, Some(third)) 

scala> val myList2:List[Option[Int]] = List(1, None, 2) 
myList2: List[Option[Int]] = List(Some(1), None, Some(2)) 
+0

Да, это то, что я искал. – javadba

3

Потому что это приведет к некоторой серьезной двусмысленности.

Проверьте приведенный ниже фрагмент (на основе предлагаемого образца).

List("apple", "hello", "orange") 

ли выше код List[Option[String]] или List[String], ну и являются допустимыми типами, какой из них выбрать?

UPDATE:

Давайте возьмем другой пример случай класса (Option случай класса с 2-х случаях Some и None):

abstract class Superhero 
case class Superman(health : Int) extends Superhero 
case class Spiderman(health: Int) extends Superhero 

Сейчас мы сталкиваемся с другой двусмысленности, если мы говорим, : List[Superhero](100,100), Является первым 100 для Супермена или это для Человека-паука, то же самое для следующего 100.

+0

Я уточнил вопрос с дополнительной опцией. По мере того как он стоит, Option/Some кажется излишне интрузивным/многословным. – javadba

+0

Я не был ниспроверен :) – Ankur

+0

@javadba: Пожалуйста, см. Обновленный ответ для вашего обновленного вопроса. – Ankur

4

В дополнение к Ank Ответ ур, Option является Монадой в Скале, означает, что он полностью реализует map, flatMap.

Таким образом, вы можете использовать его в for comprehensions:

def sum(a: Some[Int], b: Some[Int]): Int = { 
     for { 
     a <- maybeA 
     b <- maybeB 
     ... 
     } yield { 
     a + b 
     } 
    } getOrElse 0 

Или map над его содержимое: val a = Some(5); a map (3 +) // gives you Some(8)

В Тип подписи монадических методов являются сложными и трудными для компилятора, чтобы иметь дело с.

Больше двусмысленности в отношении идентичности между Optional[A] и A бесполезно и просто невозможно.

Многословность

Ваше заявление не обоснованным. На практике вы найдете scala.Option чрезвычайно мощным.

Скажем, у вас есть:

def methodA: Option[ComplexType] 
def methodB: Option[MoreComplexType] 
def methodC: Option[InsanelyComplexStructure] 

Еще цепи и проверить существование, все, что вам нужно, это понимание:

for { 
    a <- methodA 
    b <- methodB 
    c <- methodC 
} yield { 
    // now this gets executed only if all the 3 methods return Some() 
} 

Это становится чрезвычайно мощным. Глубоко вложенные, если утверждения являются плохой старой памятью.

+0

AFA подписи типов: как насчет второй представленной альтернативы - в которой явно указан тип карты List [Option [String]]? Часть, которая меня беспокоит, «боксирует» каждый элемент в списке с Some ('foo') – javadba

+0

Вторая альтернатива (добавленная после ваших комментариев и от Ankur) содержит информацию о наборе: «Option»: List [Option [String] ]. Я в порядке с этим. Есть ли какой-либо механизм, чтобы избежать элемента Some ('foo') для КАЖДОГО элемента в списке? – javadba

+0

'val l = None :: List (2, 4) .map (Some (_))', если у вас есть пучки Some? – scand1sk

4

Не думаю, что я груб, но ответ , потому что компилятор не является каким-то волшебником, который должен угадать ваши пожелания..

Это поможет вам в случае, если есть шаблонное (тип умозаключение, неявные преобразования), но весь смысл компилятора (по крайней мере, для языка с системой типов) является поймать неоднозначные ситуации, как

val results :List[Option[String]] = ("apple", None, "orange")

и кричать на вас Эй, чувак, ты, должно быть, делаешь что-то не так!. Вы в основном спрашиваете, почему компилятор не позволяет мне назначать собаку кошке, оранжевой на яблоко или trick sorter game, и когда язык допускает такие трюки some very bad and nasty things are happen.

for (fruit <- results) println(fruit) 

Как язык должен знать, что вы хотите напечатать базовое необоснованное значение, а не сам вариант? Что делать, если вы используете какую-то другую функцию? Что делать, если у меня есть Option[Option[String]]? Понимаете, есть много вещей, которые нужно учитывать, и если мы действительно считаем, что написание типичной проблемы является реальной проблемой в этом конкретном случае, мы должны сесть и перечислить все эти случаи в большой книге, и каждый должен проверить это, чтобы понять все возможные последствия в противном случае код непредсказуем. Отметим также, что будут скрытые приемники производительности: например. компилятор неявно конвертирует одну коллекцию в другую, они все-таки разные классы и разные структуры и удивляют - вы не знаете где. По крайней мере, без дополнительного просмотра кода. В конце концов, почему вы не ожидаете, что

val i: List[Int] = 3 

действительный?

0

Для использования в ограниченных участках кода, вы можете использовать implicits для этого:

implicit def string2SomeString(s: String): Option[String] = Some(s) 

val l: List[Option[String]] = List("a", None, "b") 

Вы можете столкнуться с трудностями при возникновении неясностей, однако.

Более общее неявный выполнимо, но может привести к еще более неясности:

implicit def a2SomeA[A](s: A): Option[A] = Some(s) 
+0

спасибо, я добавил имплициты к моему вопросу как частичный ответ. Если вы можете сделать это более общим с использованием более высоких типов, я получу ответ. – javadba

Смежные вопросы