Scala's для понимания a не общие итерации. Это означает, что они не могут произвести каждый возможный результат, который можно произвести из итерации, например, именно то, что вы хотите сделать.
Есть три вещи, которые может сделать Scala для понимания, когда вы возвращаете значение (то есть, используя yield
). В самом простом случае это можно сделать так:
- Учитывая объект типа
M[A]
и функция A => B
(то есть, который возвращает объект типа B
, когда данный объект типа A
), возвращать объект типа M[B]
;
Например, если последовательность символов, Seq[Char]
, получить UTF-16 целое число для этого символа:
val codes = for (char <- "A String") yield char.toInt
Выражение char.toInt
преобразует Char
в сообщение Int
, поэтому String
- который неявно преобразованный в Seq[Char]
в Scala -, становится Seq[Int]
(фактически, IndexedSeq[Int]
, через некоторую магию магии Scala).
Второе, что он может сделать это:
- Указанные объекты типа
M[A]
, M[B]
, M[C]
и т.д., а также функции A
, B
, C
и т.д. в D
, возвращает объект типа M[D]
;
Вы можете представить это как обобщение предыдущего преобразования, хотя не все, что могло бы поддержать предыдущее преобразование, может обязательно поддерживать это преобразование. Например, мы могли бы производить координаты для всех координат игр battleship как это:
val coords = for {
column <- 'A' to 'L'
row <- 1 to 10
} yield s"$column$row"
В этом случае, у нас есть объекты типов Seq[Char]
и Seq[Int]
и функции (Char, Int) => String
, таким образом мы получаем обратно Seq[String]
.
Третий, и последний, вещь для понимания может сделать это:
- Учитывая объект типа
M[A]
, так что тип M[T]
имеет нулевое значение для любого типа T
а, функция A => B
, а также условие A => Boolean
, вернуть либо ноль, либо объект типа M[B]
, в зависимости от состояния;
Это сложнее понять, хотя сначала это может выглядеть просто. Давайте посмотрим на то, что выглядит просто первым, скажем, найти все гласные в последовательности символов:
def vowels(s: String) = for {
letter <- s
if Set('a', 'e', 'i', 'o', 'u') contains letter.toLower
} yield letter.toLower
val aStringVowels = vowels("A String")
Это выглядит просто: у нас есть условие, мы имеем функцию Char => Char
, и мы получаем результат, и кажется, не нуждается в «нуле» любого вида. В этом случае нуль будет пустой последовательностью, но вряд ли стоит упомянуть об этом.
Чтобы объяснить это лучше, я переключусь с Seq
на Option
. A Option[A]
имеет два подтипа: Some[A]
и None
. Очевидно, что ноль - это None
. Он используется, когда вам нужно представить возможное отсутствие значения или самого значения.
Теперь предположим, что у нас есть веб-сервер, где пользователи, которые вошли в систему и являются администраторами, получают дополнительные javascript на своих веб-страницах для задач администрирования (например, Wordpress). Во-первых, мы должны получить пользователь, если есть пользователь вошел в систему, скажем, это делается с помощью этого метода:
def getUser(req: HttpRequest): Option[User]
Если пользователь не вошел в систему, мы получаем None
, в противном случае мы получим Some(user)
, где user
- это структура данных с информацией о пользователе, который сделал запрос. Затем мы смоделируем эту операцию следующим образом:
def adminJs(req; HttpRequest): Option[String] = for {
user <- getUser(req)
if user.isAdmin
} yield adminScriptForUser(user)
Здесь легче видеть точку нуля.Когда условие ложно, adminScriptForUser(user)
не может быть выполнено, поэтому для понимания требуется что-то вместо этого, и что-то есть «ноль»: None
.
В технических терминах Scala для понимания предоставляет синтаксические сахара для операций на monads, с дополнительной операцией для монадов с нулевым значением (см. Список в той же статье).
То, что вы на самом деле хотите достичь, называется catamorphism, обычно представленным как метод fold
, что можно охарактеризовать как функцию M[A] => B
. Вы можете написать его с помощью fold
, foldLeft
или foldRight
в последовательности, но ни одна из них фактически не завершит итерацию.
Короткое замыкание возникает, естественно, из нестрогой оценки, которая по умолчанию используется в Haskell, в которой написана большая часть этих документов. Скала, как и большинство других языков, по умолчанию является строгой.
Есть три пути решения вашей проблемы:
- Используйте специальные методы
forall
или exists
, которые нацелены на ваш точный случай использования, если они не решают общую проблему;
- Используйте нестандартную коллекцию; есть Scala's
Stream
, но у него есть проблемы, которые мешают его эффективному использованию. Библиотека Scalaz может вам помочь;
- Используйте ранний возврат, так как библиотека Scala решает эту проблему в общем случае (в конкретных случаях она использует лучшие оптимизации).
В качестве примера третьего варианта, можно написать так:
def hasEven(xs: List[Int]): Boolean = {
for (x <- xs) if (x % 2 == 0) return true
false
}
Следует также отметить, что это называется «цикл», а не «для понимания», потому что Безразлично» t возвращает значение (ну, оно возвращает Unit
), так как оно не имеет ключевого слова yield
.
Подробнее о настоящей общей итерации вы можете прочитать в статье The Essence of The Iterator Pattern, которая представляет собой эксперимент Scala с концепциями, описанными в документе под тем же названием.
список forall {code}? –
добавлен код, спасибо – jbx
Вам нужно что-либо делать с элементами, пока вы их переплетаете? Если нет, то [ответ вы ищете здесь] (http://stackoverflow.com/questions/12547235/scala-forall-example). –