1
\$\begingroup\$

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?

asked Nov 27, 2013 at 10:13
\$\endgroup\$
2
  • \$\begingroup\$ Umm... I think you could easily solve the problem above with a Map (or even just a sequence of tuples) and two basic operations: filter and foldLeft. :) Although it doesn't really answer the question. \$\endgroup\$ Commented Nov 27, 2013 at 12:50
  • \$\begingroup\$ I wanted to suggest the ternary operator (x ? y : z) instead, but I just realized it does not exist in Scala. Here is link about this topic. It is not an answer to your question, but related. \$\endgroup\$ Commented Nov 27, 2013 at 23:26

1 Answer 1

4
\$\begingroup\$

What you are describing are simply functions.

To take a related example from mathematics,

 / x, if x >= 0
abs(x) = |
 \ -x, otherwise

And you are just composing functions: f(g(x)).

You can somewhat make the correspondence to monads, but it is a bit of a stretch. I think it is more that monads are extensions of functions rather than the other way around.

flatMap would be the composition operator: o , ie (f o g)(x) = f(g(x)). And unit would just be the identity operation: I(x) = x.

The three monad laws:

  • Associativity: f o (g o h) = (f o g) o h
  • Left unit: I o f = f
  • Right unit: f o I = f

So instead of defining your If class, you can just stick to def, the usual function definition. Functional programming!!! In your case you can compose all your functions in any order since they always input/output Foo type. You can compose functions in Scala with val h = f _ compose h _, or using andThen.

answered Nov 28, 2013 at 1:58
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.