2011-05-26 15 views
7

我想知道if … else是否可以在Predef中通過特殊的編譯器處理實現,與classOf[A]的處理方式類似:定義在Predef中,實現由編譯器填充。當然,很多人會發現安心知道if始終是if,並且else始終是else,無論上下文如何。但是,將定義爲結果類型if上的一種方法會將其從關鍵字列表中刪除,並允許庫設計人員定義其自己的else方法。 (我知道我可以使用任何關鍵字作爲帶反引號的標識符,但類似`else`的代碼在代碼中看起來很糟糕。)這種方法可用於在諸如this one, discussed on the mailing list之類的情況下討論的情況,在這種情況下人們在定義時被迫使用otherwise方法實際上應該被命名爲else。 (還討論了SO herehere。)Scala的「if ... else」是否已經作爲庫函數實現?

所以:

  • 請問這樣的做法是可行的,即使是在理論上,還是它打破斯卡拉一些基本原則是什麼?
  • 缺點是什麼?

回答

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 ...,這與我在此處執行的方式非常相似。

3

不只是if-else,但任何語言功能可以在被稱爲「Scala的虛擬化」

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

這在斯坦福PPL構成悅庭項目的基礎語言的一個分支覆蓋,也是斯卡拉歐盟撥款資助的研究的核心。所以你可以合理地期待它在未來某個時候成爲核心語言的一部分。

+0

大知道這個!這確實看起來像是下一個合乎邏輯的步驟......我期待着未來:-) – 2011-05-26 14:04:24

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端口我幾年前寫的樂趣。]

+0

非常感謝這個非常好的概念證明!我意識到這可以做到這一點。我的問題是,如果當前形式的「如果......其他」可以作爲圖書館功能來實施。我認爲你和金斯貝爾已經證明它是。 – 2011-05-26 14:06:18

+0

爲什麼在這個答案downvote沒有評論? – 2011-05-27 08:46:24

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 
+0

選項從2.10開始摺疊 – 2012-10-14 12:54:23