Take the 2-minute tour ×

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 Unknown(null) which is not as elegant as I'd hoped. What do you think I could do to improve this design?

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: a usage example of the current implementation follows

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))

And a test snippet:

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));

undefinedUnplayedMatch.winner.get must be equalTo(Team("B")); 
undefinedUnplayedMatch.loser.get must be equalTo(Team("D"));

UPDATE - CURRENT IDEA : 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:

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 newDefiner(): B = {


  def filter(p: A => Boolean): Determine[A] = {
    if (p(cachedDefiner()))

  def foreach(b: A => Unit): Unit = {

  private def cachedDefiner(): A = {
    if (value == null)
      value = definer()
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 got rid of the set & 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.

share|improve this question
Not worrying about implementation, can you give some examples on how you would use such a monad using flatMap or for comprehensions? Your implementation is currently lacking the flatMap method which would define the semantic on your monad. –  huynhjl Nov 13 '11 at 16:31
I have updated the question with the test usage I'm giving to it right now. I recognize that my implementation is too clumsy to take advantage of for comprehensions at the moment, basically it is a port of an observer pattern in Java that is missing scala syntactic sugar. –  ilcavero Nov 13 '11 at 17:19
It's not very clear from your examples what you're trying to accomplish in making the Unknown[A] monad. Can you tell us a little more about the application that will use this library? –  dyross Nov 13 '11 at 18:24
@ilcavero, can you have a look at artima.com/pins1ed/for-expressions-revisited.html#23.6 and see how to restructure your code using flatMap? –  huynhjl Nov 13 '11 at 19:47
@DavidY.Ross the idea is to be able to build a bracket of matches, where a match does not necessarily have the contenders or the result defined because the contenders might be still unknown if they depend on the result of previous match, and the result might be known if the game has not been played yet. The monad container allows to abstract the matches away from the fact that the contenders and/or result are unknown. –  ilcavero Nov 14 '11 at 1:58
show 7 more comments

1 Answer

For a simple approach, you don't need monads, with partial application is enough:

//some utilities
type Score=(Int,Int)
case class MatchResult[Team](winner:Team,loser:Team)

//assume no ties
def playMatch[Team](home:Team,away:Team)(score:Score)= 
  if (score._1>score._2) MatchResult(home,away) 
  else MatchResult(away,home)

//defined played match
val dpm= playMatch("D","E")(1,0)
//defined unplayed match, we'll apply the score later
val dum= playMatch("A","B")_

// a function that takes the dum score and applies it 
// to get a defined played match from  an undefined one
// still is a partial application of match because we don't have the final result yet
val uumWinner= { score:Score => playMatch (dpm.winner,dum(score).winner) _ }
val uumLoser= { score:Score => playMatch (dpm.loser,dum(score).loser)  _}

//apply the scores 
uumWinner (2,4)(3,1)
uumLoser (2,4)(0,1)

//scala> uumWinner (2,4)(3,1)
//res6: MatchResult[java.lang.String] = MatchResult(D,B)
//scala> uumLoser (2,4)(0,1)
//res7: MatchResult[java.lang.String] = MatchResult(A,E)

This is a starting point, I'm pretty sure it can be further refined. Maybe there we'll find the elusive monad. But I think an applicative functor will be enough. I'll give another pass later...

share|improve this answer
this is a very interesting alternative, the major weakness I see is that it is imposing an order in the definition of the results, and also it is harder to visualize the bracket progression without Match objects. –  ilcavero Nov 19 '11 at 0:09
add comment

Your Answer


