Note that there are some explanatory texts on larger screens.

plurals
  1. POhow to implement this future/state concept as a monad in scala
    primarykey
    data
    text
    <p>I'm trying to implement a container for a match (like in sports) result so that I can create matches between the winners of other matches. This concept is close to what a future monads is as it contains a to be defined value, and also close to a state monad as it hides state change. Being mostly a begginer on the topic I have implemented an initial version in scala that is surely improvable. I added a get method that I'm not sure was a good idea, and so far the only way to create a value would be <code>Unknown(null)</code> which is not as elegant as I'd hoped. What do you think I could do to improve this design?</p> <pre><code>case class Unknown[T](t : T) { private var value : Option[T] = Option(t) private var applicatives: List[T =&gt; Unit] = Nil def set(t: T) { if (known) { value = Option(t) applicatives.foreach(f =&gt; f(t)) applicatives = Nil } else { throw new IllegalStateException } } def get : T = value.get def apply(f: T =&gt; Unit) = value match { case Some(x) =&gt; f(x); case None =&gt; applicatives ::= f } def known = value == None } </code></pre> <p><strong>UPDATE</strong>: a usage example of the current implementation follows</p> <pre><code>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 =&gt; { if (result._1 &gt; result._2) { home.apply(t =&gt; winner.set(t)) visit.apply(t =&gt; loser.set(t)) } else { home.apply(t =&gt; loser.set(t)) visit.apply(t =&gt; winner.set(t)) } }) } </code></pre> <p>And a test snippet:</p> <pre><code>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")); </code></pre> <p><strong>UPDATE - CURRENT IDEA :</strong> I haven't had much time to work on this because my laptop broke down, but I though it would be useful to write the monad I have so far for those who are interested:</p> <pre><code>sealed abstract class Determine[+A] { def map[B](f: A =&gt; B): Determine[B] def flatMap[B](f: A =&gt; Determine[B]): Determine[B] def filter(p: A =&gt; Boolean): Determine[A] def foreach(b: A =&gt; Unit): Unit } final case class Known[+A](value: A) extends Determine[A] { def map[B](f: A =&gt; B): Determine[B] = Known(f(value)) def flatMap[B](f: A =&gt; Determine[B]): Determine[B] = f(value) def filter(p: A =&gt; Boolean): Determine[A] = if (p(value)) this else Unknown def foreach(b: A =&gt; Unit): Unit = b(value) } final case class TBD[A](definer: () =&gt; A) extends Determine[A] { private var value: A = _ def map[B](f: A =&gt; B): Determine[B] = { def newDefiner(): B = { f(cachedDefiner()) } TBD[B](newDefiner) } def flatMap[B](f: A =&gt; Determine[B]): Determine[B] = { f(cachedDefiner()) } def filter(p: A =&gt; Boolean): Determine[A] = { if (p(cachedDefiner())) this else Unknown } def foreach(b: A =&gt; 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 =&gt; B): Determine[B] = this def flatMap[B](f: Nothing =&gt; Determine[B]): Determine[B] = this def filter(p: Nothing =&gt; Boolean): Determine[Nothing] = this def foreach(b: Nothing =&gt; Unit): Unit = {} } </code></pre> <p>I got rid of the set &amp; get and now the TBD class receives instead a function that will define provide the value or null if still undefined. This idea works great for the map method, but the rest of the methods have subtle bugs.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload