8

で行われているのと同様の方法で、特別なコンパイラ処理で にif … else実装できたのではないかと思っています。定義は にあり、実装はコンパイラによって埋められます。PredefclassOf[A]Predef

確かに、コンテキストに関係なく、は常にであり、はif常にであると知っていると安心する人が多いでしょう。ただし、結果の型のメソッドとして定義すると、キーワードのリストから削除され、ライブラリ設計者が独自のメソッドを定義できるようになります。(バックティックを使用して任意のキーワードを識別子として使用できることは知っていますが、コードではひどいように見えます。)このような方法は、メーリングリストで議論されているこのような状況で議論する場合に役立ちます。実際に名前を付ける必要があるメソッドを定義するときに使用します。( SO hereおよびhereについても説明されていますifelseelseelseifelse`else`otherwiseelse.)

そう:

  • そのようなアプローチは理論上でも可能でしょうか? それとも、Scala の基本的な原則を破りますか?
  • 欠点は何ですか?
4

4 に答える 4

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/TiarkRompf/scala-virtualized

これは、スタンフォード PPL の Delite プロジェクトの基礎を形成し、Scala の EU 助成金によって資金提供されている研究の中心でもあります。したがって、将来のある時点でそれがコア言語の一部になることは当然期待できます。

于 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") }
}

[注: 私のタイプ fu はかなり弱いです。これを妥当な時間枠内でコンパイルするには、少しごまかす必要がありました。Scala の型システムをよく理解している人は、それを修正したいと思うかもしれません。また、今見てみると、8 つのクラス、特性、およびオブジェクト (そのうちの 2 つは抽象的) は、少し過剰に設計されているように見えます ;-) ]

もちろん、パターンマッチングも同様です。パターン マッチングを使用する言語では、パターン マッチングの方が一般的なので、他の種類の条件は必要ありません。

[ところで: これは基本的に、私が数年前に楽しみのために書いたこの Ruby コードの移植です。]

于 2011-05-26T12:22:05.213 に答える