Как определить тернарный оператор в Scala, который сохраняет ведущие маркеры?

Я пишу генератор кода, который производит вывод Scala.

Я должен эмулировать тернарный оператор таким способом который маркерное продвижение до'?' останьтесь неповрежденными.

например, преобразуйте выражение c ? p : q кому: c something. Простое if(c) p else q приводит мои критерии к сбою, поскольку это требует помещения if( прежде c.

Моя первая попытка (все еще использующий c/p/q как выше)

c match { case(true) => p; case _ => q }

другая опция, которую я нашел, была:

class ternary(val g: Boolean => Any) { def |: (b:Boolean) = g(b) }

implicit def autoTernary (g: Boolean => Any): ternary = new ternary(g)

который позволяет мне писать:

c |: { b: Boolean => if(b) p else q }

Мне нравится общий вид второй опции, но есть ли способ сделать это менее подробным?

Спасибо

9
задан Alex R 24 April 2010 в 19:54
поделиться

2 ответа

Несмотря на то, что синтаксис не вычисляется в ожидаемом порядке - он связывает условие с первым вариантом! - вы можете создать свой собственный тернарный оператор следующим образом:

class IfTrue[A](b: => Boolean, t: => A) { def |(f: => A) = if (b) t else f }
class MakeIfTrue(b: => Boolean) { def ?[A](t: => A) = new IfTrue[A](b,t) }
implicit def autoMakeIfTrue(b: => Boolean) = new MakeIfTrue(b)

Уловка состоит в том, чтобы интерпретировать ? как метод для объекта MakeIfTrue , который привязывает условие к объекту для возврата в «истинном» случае. Результирующий объект IfTrue теперь использует метод | в качестве запроса для оценки условия, возвращая сохраненную опцию true, если условие истинно, или только что переданную опцию, если она ложный.

Обратите внимание, что я использовал такие вещи, как => A вместо просто A - параметры по имени - чтобы не оценивать выражение, если оно не используется на самом деле. Таким образом, вы будете оценивать только ту сторону, которая вам действительно нужна (как оператор if).

Давайте посмотрим на это в действии:

scala> List(1,3,2).isEmpty ? "Empty" | "Nonempty"
res0: java.lang.String = Nonempty

scala> (4*4 > 14) ? true | false
res1: Boolean = true

scala> class Scream(s: String) { println(s.toUpperCase + "!!!!") }
defined class Scream

scala> true ? new Scream("true") | new Scream("false")
TRUE!!!!
res3: Scream = Scream@1ccbdf7

(PS Чтобы избежать путаницы с библиотекой Actor ? , вам, вероятно, следует назвать ее как-то иначе, например |? .)

16
ответ дан 4 December 2019 в 06:40
поделиться

Вы можете использовать что-то вроде этого

sealed trait TernaryOperand[A] {
  def >(q: => A): A
}

case class TernarySecond[A](val p: A) extends TernaryOperand[A] {
  def >(q: => A) = p
}

case class TernaryThird[A]() extends TernaryOperand[A] {
  def >(q: => A) = q
}

implicit def ternary(c: Boolean) = new {
  def ?[A](p: => A): TernaryOperand[A] = if (c) TernarySecond(p) else TernaryThird()
}

val s1 = true ? "a" > "b"
println(s1) //will print "a"

val s2 = false ? "a" > "b"
println(s2) //will print "b"

Этот код преобразует любое логическое значение в анонимный тип, который имеет метод с именем ? . В зависимости от значения логического значения этот метод вернет либо TernarySecond , либо TernaryThird . У них обоих есть метод под названием > , который возвращает второй или третий операнд соответственно.

5
ответ дан 4 December 2019 в 06:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: