我想知道if … else
是否可以通过特殊的编译器处理在Predef
中实现,与classOf[A]
的方式类似:定义在{{1}实现由编译器填充。
当然,许多人会惊讶地发现,Predef
始终是if
,而if
始终是else
,无论上下文如何。但是,将else
定义为结果类型else
的方法会将其从关键字列表中删除,并允许库设计者定义自己的if
方法。 (我知道我可以使用任何关键字作为带反引号的标识符,但else
之类的内容在代码中看起来很糟糕。)此类方法在{{{}等情况下讨论的情况下非常有用3}},在定义实际应该命名为`else`
的方法时,人们被迫使用otherwise
。 (也在SO this one, discussed on the mailing list和here上进行了讨论。)
所以:
答案 0 :(得分:10)
也许我不理解您的问题,但您已经可以将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 ...
的实现与我在这里实现的方式非常相似。
答案 1 :(得分:8)
简短的回答是“是”;某些谓词上的分支逻辑可以实现为库函数。
值得指出的是,正如Viktor Klang和其他人所指出的那样,if / 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
布尔值上的分支逻辑也是一个折叠,你可以相应地pimp布尔值。注意使用by-name参数来实现延迟评估。如果没有此功能,则无法实现此类实现。
// 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
答案 2 :(得分:3)
不只是if-else
,而且任何语言功能都可以在称为“Scala Virtualized”的语言分支中重写
https://github.com/TiarkRompf/scala-virtualized
这构成了斯坦福大学PPL的Delite项目的基础,也是由Scala的欧盟资助资助的研究的核心。因此,您可以合理地期望它在未来的某个时刻成为核心语言的一部分。
答案 3 :(得分:3)
任何面向对象的语言(或带有运行时多态性的任何语言)都可以将条件实现为库特性,因为方法调度已经是一种更通用的条件形式。例如,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个类,特征和对象,其中两个是抽象的,似乎有点过度设计;-)]
当然,模式匹配也是如此。任何具有模式匹配的语言都不需要其他类型的条件,因为无论如何模式匹配都更为通用。
[BTW:这基本上是this Ruby code的一个端口我几年前写的很有趣。]