Может ли Scala «если… еще» быть реализован как библиотечная функция? - PullRequest
7 голосов
/ 26 мая 2011

Мне интересно, если бы if … else мог быть реализован в Predef со специальной обработкой компилятором, аналогично тому, что делается с classOf[A]: определение в Predef, реализация заполнена компилятором.

Конечно, многим людям было бы приятно узнать, что if - это всегда if, а else - это всегда else, независимо от контекста. Однако определение else в качестве метода для типа результата if приведет к удалению его из списка ключевых слов и позволит разработчикам библиотек определять свои собственные методы else. (я знаю, что могу использовать любое ключевое слово в качестве идентификатора с обратными галочками, но что-то вроде `else` просто ужасно выглядит в коде.) Такие методы могут быть полезны в случаях, обсуждаемых в ситуациях, таких как , эта , обсуждается в списке рассылки , где люди вынуждены использовать otherwise при определении методов, которые на самом деле должны называться else. (Также обсуждается на SO здесь и здесь .)

Итак:

  • Возможен ли такой подход даже в теории или он нарушает какой-то фундаментальный принцип в Scala?
  • Какими бы были недостатки?

Ответы [ 4 ]

10 голосов
/ 26 мая 2011

Возможно, я не понимаю ваш вопрос, но вы уже можете реализовать if ... else ... как библиотечную функцию.Подумайте об этом:

class If[A](condition: =>Boolean)(ifBlock: =>A) {
  def els(elseBlock: =>A):A = condition match {
    case true => ifBlock
    case false => elseBlock
  }
}

new If(2==3)(
  println("equal")
) els (
  println("not equal")
)

Конечно, это не делает точно , что делает if ... else ..., но я думаю, что с некоторой полировкой это произойдет.Однажды я реализовал очень простой интерпретатор для языка, для которого встроено сопоставление с шаблоном, и if ... else ... реализован почти так же, как здесь.

8 голосов
/ 26 мая 2011

Краткий ответ - «да»;Логика ветвления в некотором предикате может быть реализована в виде библиотечной функции.

Стоит отметить, что, как заметил Виктор Кланг и другие, если / else по сути сворачивает логическое значение.Сворачивание - это то, что мы часто делаем - иногда оно четкое и явное, а иногда нет.

// Either#fold is explicit
scala> Left[String, Double]("fail") fold(identity, _ + 1 toString)
res0: java.lang.String = fail

scala> Right[String, Double](4) fold(identity, _ + 1 toString)
res1: java.lang.String = 5.0

Сворачивание параметра невозможно выполнить явно, но мы делаем это постоянно.

// Option has no fold - wont compile!
Some(5) fold(1+, 0)

// .. but the following is equivalent and valid
scala> Some(5) map(1+) getOrElse(0)
res3: Int = 6

Логика ветвления на логическом значении также является фолдом, и вы можете соответствующим образом конвертировать логическое значение.Обратите внимание на использование параметров по имени для достижения ленивой оценки.Без этой функции такая реализация была бы невозможна.

// pimped Boolean - evaluates t when true, f when false
class FoldableBoolean(b: Boolean) {
  def fold[A](t: => A, f: => A) =
    if(b) t else f
}

implicit def b2fb(b: Boolean) = new FoldableBoolean(b)

Теперь мы можем сложить логические значения:

scala> true fold("true!", "false")
res24: java.lang.String = true!

scala> false fold("true!", "false")
res25: java.lang.String = false
3 голосов
/ 26 мая 2011

Любой объектно-ориентированный язык (или любой язык с полиморфизмом времени выполнения) могут реализовывать условные выражения как библиотечную функцию, поскольку диспетчеризация метода уже является более общей формой условных вычислений в любом случае. Например, Smalltalk не имеет абсолютно никаких условий, кроме отправки по методу.

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

В Scala это может выглядеть примерно так:

trait MyBooleanLike {
  def iff[T <: AnyRef](thenn: => T): T
  def iffElse[T](thenn: => T)(els: => T): T
  def &&(other: => MyBoolean): MyBoolean
  def ||(other: => MyBoolean): MyBoolean
  def nott: MyBoolean
}

trait MyTruthiness extends MyBooleanLike {
  def iff[T](thenn: => T) = thenn
  def iffElse[T](thenn: => T)(els: => T) = thenn
  def &&(other: => MyBoolean) = other
  def ||(other: => MyBoolean) = MyTrue
  def nott = MyFalse
}

trait MyFalsiness extends MyBooleanLike {
  def iff[T](thenn: => T): T = null.asInstanceOf[T]
  def iffElse[T](thenn: => T)(els: => T) = els
  def &&(other: => MyBoolean) = MyFalse
  def ||(other: => MyBoolean) = other
  def nott = MyTrue
}

abstract class MyBoolean extends MyBooleanLike

class MyTrueClass extends MyBoolean with MyTruthiness {}
class MyFalseClass extends MyBoolean with MyFalsiness {}

object MyTrue extends MyTrueClass {}
object MyFalse extends MyFalseClass {}

Просто добавьте небольшое неявное преобразование:

object MyBoolExtension {
  implicit def boolean2MyBoolean(b: => Boolean) =
    if (b) { MyTrue } else { MyFalse }
}

import MyBoolExtension._

И теперь мы можем использовать его:

object Main extends App {
  (2 < 3) iff { println("2 is less than 3") }
}

[Примечание: мой тип-фу довольно слабый. Мне пришлось немного обмануть, чтобы компилировать это в разумные сроки. Кто-то с лучшим пониманием системы типов Scala может захотеть исправить это. Кроме того, теперь, когда я смотрю на это, 8 классов, черты и объекты, два из которых абстрактные, кажутся немного перегруженными ;-)]

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

[Кстати: это в основном порт этого кода Ruby Я написал пару лет назад для забавы.]

3 голосов
/ 26 мая 2011

Не только if-else, но любая языковая функция может быть переопределена в ветви языка, известного как "Scala Virtualized"

https://github.com/TiarkRompf/scala-virtualized

Этолежит в основе проекта Delite в Стэнфордском PPL, а также лежит в основе исследований, финансируемых грантом Scala в ЕС.Таким образом, вы можете разумно ожидать, что он станет частью основного языка в будущем.

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