8

我想知道是否if … else可以Predef通过特殊的编译器处理实现 in ,其方式类似于正在执行的操作classOf[A]:定义在 in Predef,实现由编译器填充。

诚然,无论在什么情况下,很多人都会放心,知道 anif始终是 an if,并且 anelse始终是 an 。else但是,将else结果类型定义为方法if会将其从关键字列表中删除,并允许库设计者定义自己的else方法。(我知道我可以使用任何关键字作为带有反引号的标识符,但是`else`在代码中看起来很糟糕。)在这种情况下讨论的情况下,这些方法可能很有用,在邮件列表中讨论过,人们被迫otherwise在定义实际上应该命名的方法时使用else。(也在这里这里讨论过.)

所以:

  • 即使在理论上,这种方法是否可行,还是它违反了 Scala 中的一些基本原则?
  • 缺点是什么?
4

4 回答 4

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 ...其实现方式与我在这里所做的非常相似。

于 2011-05-26T08:54:55.227 回答
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

布尔值上的分支逻辑也是一个折叠,您可以相应地拉皮条布尔值。注意使用按名称参数来实现惰性求值。没有这个特性,这样的实现是不可能的。

// 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
于 2011-05-26T14:55:29.820 回答
3

不仅如此if-else任何语言特性都可以在称为“Scala Virtualized”的语言分支中被覆盖

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

这构成了斯坦福 PPL 的 Delite 项目的基础,也是 Scala 欧盟资助的研究的核心。所以你可以合理地期望它在未来的某个时候成为核心语言的一部分。

于 2011-05-26T12:14:28.527 回答
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 个类、特征和对象,其中两个是抽象的,似乎有点过度设计了 ;-) ]

当然,模式匹配也是如此。任何具有模式匹配的语言都不需要其他类型的条件,因为无论如何模式匹配更通用。

[顺便说一句:这基本上是我几年前为了好玩而写的这段 Ruby 代码的移植。]

于 2011-05-26T12:22:05.213 回答