I found myself writing code of the form...
val foo : Foo = ???
val step1 : Foo = {
if ( someCharacteristic( foo ) )
someTransformation( foo )
else
foo
}
val step2 : Foo = {
if ( otherCharacteristic( foo ) )
otherTransformation( foo )
else
foo
}
val result = step2;
That seemed awkward, and it seemed like this sort of ugly stepwise processing could be monadified. I've used but not written Scala monads; I thought I'd give it a shot. What I have seems to work, but I found proving the monad laws surprisingly challenging. I'm not sure I've got a valid monad, and wonder whether there is some subtle problem that would bite me someday if I haven't. FWIW, here's the code, any comments would be very welcome.
package dumbmonad;
import scala.language.implicitConversions;
object If {
implicit def unwrap[T]( ift : If[T] ) = ift.value;
def evaluate[T]( ift : If[T] ) : T = if ( ift.condition( ift.value ) ) ift.transformation( ift.value ) else ift.value;
def flatten[T]( outer : If[If[T]] ) : If[T] = evaluate( outer );
def apply[T]( value : T ) : If[T] = apply( value, _ => false, identity );
}
case class If[T]( val value : T, val condition : (T)=>Boolean, val transformation : (T)=>T ) {
lazy val evaluate : T = If.evaluate( this );
def map[S]( f : (T) => S ) : If[S] = If( f( this.evaluate ) )
def flatMap[S]( f : (T) => If[S] ) : If[S] = If.flatten( this.map( f ) )
}
I use it like this:
import dumbmonad._;
import dumbmonad.If._;
val foo : Foo = ???
for {
a <- If( foo, someCharacteristic, someTransformation )
b <- If( a, otherCharacteristic, otherTransformation )
} yield b;
val result : Foo = b; // implicit call to If.unwrap( ... )
Is this terrible?
Map
(or even just a sequence of tuples) and two basic operations:filter
andfoldLeft
. :) Although it doesn't really answer the question. \$\endgroup\$