私は他のマッチの勝者の間でマッチを作ることができるように(スポーツのような)マッチのコンテナを実装しようとしています。このコンセプトは、未来のモナドは、それが定義された値を含み、状態変化を隠す状態モナドの近くにあるので、近いものです。主にトピックの初心者であるため、私はscalaで初期バージョンを実装しましたが、それは確かに改善可能です。私はgetメソッドを追加しました。これは良いアイデアではありませんでした。値を作成する唯一の方法は、Unknown(null)
です。これは私が望むほどエレガントではありません。このデザインを改善するために私は何ができると思いますか?この未来/状態概念をスカラーのモナドとして実装する方法
case class Unknown[T](t : T) {
private var value : Option[T] = Option(t)
private var applicatives: List[T => Unit] = Nil
def set(t: T) {
if (known) {
value = Option(t)
applicatives.foreach(f => f(t))
applicatives = Nil
} else {
throw new IllegalStateException
}
}
def get : T = value.get
def apply(f: T => Unit) = value match {
case Some(x) => f(x);
case None => applicatives ::= f
}
def known = value == None
}
UPDATE:
val definedUnplayedMatch = Match(Unknown(Team("A")), Unknown(Team("B")), Unknown(null));
val definedPlayedMatch = Match(Unknown(Team("D")), Unknown(Team("E")), Unknown((1,0)));
val undefinedUnplayedMatch = Match(Unknown(null), Unknown(null), Unknown(null));
definedUnplayedMatch.winner.apply(undefinedUnplayedMatch.home.set(_))
definedPlayedMatch.winner.apply(undefinedUnplayedMatch.visit.set(_))
undefinedUnplayedMatch.result.set((3,1))
definedUnplayedMatch.result.set((2,4))
undefinedUnplayedMatch.winner.get must be equalTo(Team("B"));
undefinedUnplayedMatch.loser.get must be equalTo(Team("D"));
UPDATE - CURRENT IDEA:現在の実装での使用例
case class Match(val home: Unknown[Team], val visit: Unknown[Team], val result: Unknown[(Int, Int)]) {
val winner: Unknown[Team] = Unknown(null)
val loser: Unknown[Team] = Unknown(null)
result.apply(result => {
if (result._1 > result._2) {
home.apply(t => winner.set(t))
visit.apply(t => loser.set(t))
} else {
home.apply(t => loser.set(t))
visit.apply(t => winner.set(t))
}
})
}
とテストスニペットは次の私が持っていなかったを私のラップトップが故障したのでこれに取り組むのに多くの時間が必要ですが、私はモナド私が興味を持っている人のために、これまで持っている:
sealed abstract class Determine[+A] {
def map[B](f: A => B): Determine[B]
def flatMap[B](f: A => Determine[B]): Determine[B]
def filter(p: A => Boolean): Determine[A]
def foreach(b: A => Unit): Unit
}
final case class Known[+A](value: A) extends Determine[A] {
def map[B](f: A => B): Determine[B] = Known(f(value))
def flatMap[B](f: A => Determine[B]): Determine[B] = f(value)
def filter(p: A => Boolean): Determine[A] = if (p(value)) this else Unknown
def foreach(b: A => Unit): Unit = b(value)
}
final case class TBD[A](definer:() => A) extends Determine[A] {
private var value: A = _
def map[B](f: A => B): Determine[B] = {
def newDefiner(): B = {
f(cachedDefiner())
}
TBD[B](newDefiner)
}
def flatMap[B](f: A => Determine[B]): Determine[B] = {
f(cachedDefiner())
}
def filter(p: A => Boolean): Determine[A] = {
if (p(cachedDefiner()))
this
else
Unknown
}
def foreach(b: A => Unit): Unit = {
b(cachedDefiner())
}
private def cachedDefiner(): A = {
if (value == null)
value = definer()
value
}
}
case object Unknown extends Determine[Nothing] {
def map[B](f: Nothing => B): Determine[B] = this
def flatMap[B](f: Nothing => Determine[B]): Determine[B] = this
def filter(p: Nothing => Boolean): Determine[Nothing] = this
def foreach(b: Nothing => Unit): Unit = {}
}
Iがセット&取得し、今TBDクラスではなく、まだ未定義の場合、値はnullを提供定義する機能を受信を処分しました。この考え方はmapメソッドにとっては効果的ですが、残りのメソッドは微妙なバグがあります。
「flatMap」または「for」内包語を使用してモナドを使用する方法についていくつかの例を挙げることはできますか?あなたの実装は現在、あなたのモナドのセマンティックを定義する 'flatMap'メソッドがありません。 – huynhjl
私は今使っているテストの使い方で質問を更新しました。現時点では、私の実装は理解が難しいと認識していますが、基本的にはJavaのオブザーバパターンのポートであり、スカラ構文的な砂糖が足りません。 – ilcavero
Unknown [A]モナドを作る際に達成しようとしていることは、あなたの例からあまり明確ではありません。このライブラリを使用するアプリケーションについてもう少し詳しく教えてください。 – dyross