我想實現一個匹配容器(如運動)的結果,以便我可以在其他匹配的獲勝者之間創建匹配。這個概念接近於未來的monad,因爲它包含一個被定義的價值,並且接近一個狀態monad,因爲它隱藏了狀態變化。作爲主題上的大多數人,我已經在scala中實現了初始版本,這肯定是可以改進的。我添加了一個get方法,我不知道這是一個好主意,到目前爲止,創建一個值的唯一方法是Unknown(null)
,這不像我所希望的那樣優雅。你認爲我可以做些什麼來改進這種設計?如何在scala中實現這個未來/狀態概念作爲monad
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:目前執行的使用示例如下
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))
}
})
}
和測試片段:
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"));
更新 - 當前的IDEA:我沒有因爲我的筆記本電腦壞了,所以我有很多時間來處理這個問題,但我認爲編寫monad會很有用我至今對於那些有興趣誰:
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 = {}
}
我擺脫了一套&得到現在的TBD類接收,而不是將定義如果仍不明確提供值或空值的函數。這個想法對於map方法非常有用,但其餘的方法都有微妙的錯誤。
不用擔心實現,你可以舉一些例子說明你將如何使用這樣一個使用'flatMap'或'for'解析的monad?你的實現目前缺乏定義monad上的語義的'flatMap'方法。 – huynhjl
我已經用我現在給它的測試用法更新了這個問題。我意識到我的實現過於笨拙,無法利用當前的理解,基本上它是Java中觀察者模式的一個端口,缺少了scala語法糖。 – ilcavero
從你的例子中不清楚你在製作未知[A] monad時想要達到的效果。你能告訴我們更多關於將使用這個庫的應用程序嗎? – dyross