ユニット処理のためのScala DSLパターン

Scalaでオペレーティングユニット用の「ミニDSL」を作成するためのパターンが表示されます。 このパターンの実装の1つは、Scala標準ライブラリ、つまりscala.concurrent.duration._にあります。 Akka [1]のドキュメントの例:



implicit val timeout = Timeout(5 seconds)
      
      





この場合、Intは“ seconds”メソッドで暗黙的にオブジェクトに変換され、関数が必要とする型を返します。



次に、周波数で動作するための「ミニDSL」の段階的な作成を検討します。 最終的には、5 kHzなどの自然な方法で周波数を設定できるようにする予定です。



パターンの実装を開始する前に、時間、信号レベル、または周波数にかかわらず、測定単位を保存するクラスを作成する必要があります。 例:



 class Frequency(val hz: BigInt) { require(hz >= 0, "Frequency must be greater or equal to zero!") def +(other: Frequency) = new Frequency(hz + other.hz) override def toString: String = hz.toString + " Hz" }
      
      





測定単位を格納するためのクラスを作成した後、考えられるすべての表現と、それらを相互に変換するための規則を識別する必要があります。 周波数の場合、これらはHz、kHz、MHz、GHzです。 例:



 sealed trait FrequencyUnitScala { def toHz(n: BigInt): BigInt def toKHz(n: BigInt): BigInt def toMHz(n: BigInt): BigInt def toGHz(n: BigInt): BigInt def convert(n: BigInt, unit: FrequencyUnitScala): BigInt } object Hz extends FrequencyUnitScala { override def toHz(n: BigInt): BigInt = n override def toGHz(n: BigInt): BigInt = toMHz(n) / 1000 override def toKHz(n: BigInt): BigInt = n / 1000 override def toMHz(n: BigInt): BigInt = toKHz(n) / 1000 override def convert(n: BigInt, unit: FrequencyUnitScala): BigInt = unit.toHz(n) } …… }
      
      





上記の実装はHz専用です。 残りは同じ方法で行われます。 これらは、記事の最後にあるリンクのgithubで表示できます。 標準のScalaライブラリの場合、変換ルールは列挙型(java.util.concurrent.TimeUnit)で指定されます。



applyメソッドでコンパニオンオブジェクトをFrequencyクラスに追加して、頻度を作成します。



 object Frequency { def apply(value: BigInt, unit: FrequencyUnitScala): Frequency = unit match { case frequency.Hz => new Frequency(value) case u => new Frequency(u.toHz(value)) } }
      
      





測定単位とその変換のルールを格納するクラスができたので、暗黙的な変換のメソッドを作成し、スコープに追加する必要があります。 「パッケージオブジェクト」を作成する方が便利です。



 trait FrequencyConversions { protected def frequencyIn(unit: FrequencyUnitScala): Frequency def Hz = frequencyIn(frequency.Hz) def kHz = frequencyIn(frequency.kHz) def MHz = frequencyIn(frequency.MHz) def GHz = frequencyIn(frequency.GHz) } package object frequency { implicit final class FrequencyInt(private val n: Int) extends FrequencyConversions { override protected def frequencyIn(unit: FrequencyUnitScala): Frequency = Frequency(n, unit) } }
      
      





暗黙の各クラスは、頻度を導出できる型を追加します。 これで、自然な方法で周波数を使用できます。 例:



 scala> import org.nd.frequency._ import org.nd.frequency._ scala> println(1 Hz) 1 Hz scala> println(1 kHz) 1000 Hz scala> println(1 MHz) 1000000 Hz scala> println(1 GHz) 1000000000 Hz
      
      





将来的には、加算と乗算の演算を追加できます。 この場合、各式を角括弧で囲むか、数字の後にドットを挿入する必要があるため、構文はそれほど自然に見えません。



 scala> val sum = (3000 kHz) + (2 MHz) sum: org.nd.frequency.Frequency = 5000000 Hz scala> println("3000 kHz + 2 MHz equals " + sum.toKHz) 3000 kHz + 2 MHz equals 5000 kHz scala> 10.Hz + 5.Hz res1: org.nd.frequency.Frequency = 15 Hz
      
      





サンプルを含む完全なソースコードは、 リポジトリで表示できます



更新

1.後置記法を使用してメソッドを呼び出すことは安全ではなく、推奨されません 。 通常の表記法でオプションを追加しました。 Googolplexに感謝します。

2.記事にFrequencyConversionsの混合物を追加しました。 velet5に感謝します



使用されたソースのリスト



1. 先物。 Akkaドキュメント。 セクション「アクターで使用」。



All Articles