Thursday, April 14, 2011

ScalaFp 02 (Choice)






Expect frequent changes.





Choice


Here is an of apect of computations: choice.


Here is ChoiceModule.
The abstract choice methods are _nothing and or.






package com.imaginej

package choice

trait ChoiceModule {
type M[+Z] <: Choice[Z]
def _nothing[Z]: M[Z]
trait Choice[+A] { self: M[A] =>
def or[B >: A](mb: => M[B]): M[B]
}
}




ChoiceMonads


The extra concrete choice monad method is withFilter.






package com.imaginej

package monad

package choice

import monad.MonadModule
import com.imaginej.choice.ChoiceModule

trait ChoiceMonadModule
extends MonadModule
with ChoiceModule {
type M[+Z] <: ChoiceMonad[Z]
trait ChoiceMonad[+A]
extends Monad[A]
with Choice[A] { self: M[A] =>
def withFilter(ap: A => Boolean) =
flatMap { a =>
if (ap(a)) {
_return(a)
} else {
_nothing
}
}
}
}




ChoiceMonad Instances


Here are some choice monad instances.







TraversableChoiceMonad.






package com.imaginej

package monad

package choice

package instances

import monad.choice.ChoiceMonadModule

object TraversableChoiceMonadObject
extends ChoiceMonadModule {
type M[+Z] = TraversableChoiceMonad[Z]
type In[-Z] = Unit
type Out[+Z] = Traversable[Z]
override def _return[Z] =
z => TraversableChoiceMonad(Traversable(z))
override def _nothing[Z] =
new TraversableChoiceMonad(Traversable())
def _close[Z]: Traversable[Z] => M[Z] =
TraversableChoiceMonad(_)
case class TraversableChoiceMonad[+A](val open: Traversable[A])
extends ChoiceMonad[A] {
override def run[B >: A](u: Unit): Traversable[B] =
this.open
override def flatMap[B](a_f_mb: A => M[B]): M[B] =
_close(for {
a <- this.open
b <- a_f_mb(a).open
} yield b)
override def or[B >: A](mb: => M[B]) =
_close(this.open ++ mb.open)
}
}





OptionChoiceMonad.




Note: options are not traversable, but we make them traversable
using an implicit conversion.






package com.imaginej

package monad

package choice

package instances

import monad.choice.ChoiceMonadModule

object OptionChoiceMonadObject
extends ChoiceMonadModule {
type M[+Z] = OptionChoiceMonad[Z]
type In[-Z] = Unit
type Out[+Z] = Option[Z]
override def _return[Z] =
z => OptionChoiceMonad(Some(z))
override def _nothing[Z] =
OptionChoiceMonad(None)
def _close[Z]: Option[Z] => M[Z] =
OptionChoiceMonad(_)
implicit def _ocm_f_tcm[Z]: M[Z] => TraversableChoiceMonadObject.M[Z] =
mz => TraversableChoiceMonadObject._close(mz.open)
case class OptionChoiceMonad[+A](val open: Option[A])
extends ChoiceMonad[A] {
override def run[B >: A](u: Unit): Option[B] =
this.open
override def flatMap[B](a_f_mb: A => M[B]): M[B] =
_close(for {
a <- this.open
b <- a_f_mb(a).open
} yield b)
override def or[B >: A](mb: => M[B]) =
_close(this.open orElse mb.open)
}
}




Implicit Choice Monads


It is convenient to define implicit choice monads for later usage.






import instances.TraversableChoiceMonadObject
import instances.OptionChoiceMonadObject

object ChoiceMonadModule {
implicit val traversableChoiceMonad =
TraversableChoiceMonadObject
implicit val optionChoiceMonad =
OptionChoiceMonadObject
}




Application


Here is an application.






package com.imaginej

package apps

import monad.choice.instances._

object UsingChoiceMonads {
def usingTraversableChoiceMonad() {
import TraversableChoiceMonadObject._
val computation =
for {
x <- _close(List(1, 2))
y <- _close(List(x + 1, x + 2))
if (x == y)
} yield (x, y)
println {
computation run ()
}
}
def usingOptionChoiceMonad() {
import OptionChoiceMonadObject._
val computation =
for {
x <- _close(Some(1))
y <- _close(Some(x + 1))
if (y >= 2)
} yield (x, y)
println {
computation run ()
}
}
def usingTwoChoiceMonads() {
import TraversableChoiceMonadObject.{ _close => _closeT, _ }
import OptionChoiceMonadObject.{ _close => _closeO, _ }
val maybeInts =
_closeT(List(_closeO(Some(1)), _closeO(None), _closeO(Some(2))))
val computation =
for {
maybeInt <- maybeInts
i <- maybeInt
if (i >= 2)
} yield i
println {
computation run ()
}
}
def main(args: Array[String]) {
usingTraversableChoiceMonad()
usingOptionChoiceMonad()
usingTwoChoiceMonads()
}
}





Running the application yields.




$ scala com.imaginej.apps.UsingChoiceMonads
List()
Some((1,2))
List(2)

No comments:

Post a Comment