Showing posts with label DSL. Show all posts
Showing posts with label DSL. Show all posts

6/2/09

Boolean Algebra Internal DSL in Scala (aka fun with Unicode names )

In Scala, operator names can be characters from the unicode set of mathematical symbols (Sm) or other symbols (So). That can lead to interesting possibilities:


val Π = Math.Pi
def √(x:Double)=Math.sqrt(x)
val x= √(9*Π)


Here, "Π" is just another constant and "√" is a function like "q".
(To use unicode in eclipse, you have to go to Preferences->General->Workspace, and change the text encoding to UTF-16)

Another example: with the ∑ and ∏ you can have define summation and the product of a sequence as follows:


def ∑(r:Range)(f:Int =>Int)=r.reduceLeft(_+ f(_))
def ∏(r:Range)(f:Int =>Int)=r.reduceLeft(_* f(_))


And now we can write:


val s= ∑(1 to 100)(x=>x^2)
val p= ∑(1 to 100 by 2)(x=>x^2)
val y= ∏(1 to 30 by 3)(_)


Of course, I'm not advocating using Scala as a substitute of a specific mathematical tool, besides, there's already a "language with symbols" (btw, I wonder if one can make a Scala "skin" that looks like APL). I'm not sure how other languages can do this (except APL maybe?), but this goes to show the power of Scala for "internal DSL".

For a slightly more complex example, let's define an internal DSL for boolean logic, with the appropriate symbols: ¬,V,Λ,and →.


class LogicBoolean(val value:Boolean) {
import LogicBoolean.¬
override def toString=value.toString

def V(b:LogicBoolean)=new LogicBoolean(this.value || b.value)
def Λ(b:LogicBoolean)=new LogicBoolean(this.value && b.value)
def →(b:LogicBoolean)=(¬(this)) V (this Λ b)
}

object LogicBoolean {
def ¬(a:LogicBoolean)=new LogicBoolean(!a.value)
implicit def boolToLogicBool(x:Boolean)=new LogicBoolean(x)
}


The only prefix operators that can be defined in Scala are ‘+’, ‘’, ‘!’ or ‘~’, so no luck for ¬. But we if we define it as a function, we can import it and use it (almost) like a prefix op. As we want an implicit conversion from boolean to our LogicBoolean class, a companion object is the ideal place to put both. By importing all the methods in the companion, we bring the ¬ operator and the implicit conversion into scope:


import LogicBoolean._

val A=true
val B=false

println("¬A :"+ ¬(A))
println("¬B :"+ ¬(B))
println("A Λ B :"+ (A Λ B))
println("A V B :"+ (A V B))
println("A → B :" + (A → B))
println("B → A :" + (B → A))


With everything in place, with a for comprehension is very easy to print the truth tables of any complex formula (just be careful with the precedence, use parenthesis):


import LogicBoolean._

val r=List(true,false)


def expr(a:Boolean,b:Boolean,c:Boolean,d:Boolean)=
( (a Λ b) V ¬(a Λ c) ) Λ ((c V d) Λ ¬(b) )

//let's print the truth table
println ("\na\tb\tc\td\t(a Λ b) V ¬(a Λ c) ) Λ ((c V d) Λ ¬(b)")
for (
a <- r; b <- r; c <- r; d <- r ) println (a+"\t"+b+"\t"+c+"\t"+d+"\t"+expr(a,b,c,d))

If you run the examples you get:


¬A :false
¬B :true
A Λ B :false
A V B :true
A → B :false
B → A :true

a b c d (a Λ b) V ¬(a Λ c) ) Λ ((c V d) Λ ¬(b)
true true true true false
true true true false false
true true false true false
true true false false false
true false true true false
true false true false false
true false false true true
true false false false false
false true true true false
false true true false false
false true false true false
false true false false false
false false true true true
false false true false true
false false false true true
false false false false false

The ability to easily adapt the language to looks like the domain is one of the main selling features of languages like Lisp. Though Scala is no way like Lisp, it can go very far in the "internal DSL" direction and provides many features to make that easy.

EDIT: Something very similar in Ruby

8/25/08

State machines using "Fluent interfaces/ DSL" in Java

I always found state machines very useful for describing particular aspects of object behavior. A classic example can be a shopping order: it can be "pending","in progress", "shipped", etc.
In my previous project, I started with a simple design using a transition matrix. I must confess it didn't work well. It was hard to explain and it grew more complex as new requirements were added. I though it would be simpler if I didn't use any "fancy OO stuff" and advanced idioms. I've should know better!
This time I wanted to try something different, and based in my previous experiments with internal DSLs with Scala and my (very limited) knowledge of the patters to achieve that in java, I just went ahead and tried to come up with something useful and understandable. This time seems to be working: although it has some "magic" behind curtains is only in the creation and is very easy to add or modify the configuration class for new or updated states and events. Other members of my project were able to add and remove states and transitions with only a brief explanation.

The basic classes are pretty simple: State and Event.

package statemachine;


public class Event {

final private String label;

public Event(String newLabel){

label=newLabel;

}

/**

* @return Returns the label.

*/

public String getLabel() {

return label;

}

public String toString(){

return label;

}

}


package statemachine;

import java.util.HashMap;

import java.util.Map;


public class State {

private final String label;

private final Map<Event,Transition> transitions= new HashMap<Event,Transition>();

//no public access to the constructor, must be in the same package

State(String newLabel){

this.label=newLabel;

}

void addTransition(Transition t){

transitions.put(t.getEvent(),t);

}

public State doEvent(Event e){

return (transitions.get(e)).getDestination();

}

/**

* @return Returns the label.

*/

public String getLabel() {

return label;

}

/**

* @return Returns the transitions.

*/

public Map<Event,Transition> getTransitions() {

return transitions;

}

}


You send a event to a sate and it returns the next state:
State newState=state.doEvent(event);
The State class holds a map of [event->state] (with the Transition class in the middle, for added effect :) )
As an extra safety measure, the State constructor and the addTransition method is accessible only to the package (well, unless you subclass it)
The "fluency" is provided by the Transition class (the useful methods return this to allow method chaining), so you can write:
new Transition(event).from(origin).to(destination)

package statemachine;

class Transition {

private State origin,destination;

private Event event;

public Transition(Event e){

event=e;

}

public Transition from(State orig){

origin=orig;

origin.addTransition(this);

return this;

}

public Transition to(State dest){

destination=dest;

return this;

}

/**

* @return Returns the destination.

*/

public State getDestination() {

return destination;

}

/**

* @return Returns the event.

*/

public Event getEvent() {

return event;

}

/**

* @return Returns the origin.

*/

public State getOrigin() {

return origin;

}

}



How this will look? Suppose you have a pretty simple FSM:















Using the previous pseudoDSL/Fluent interface will look like:

package statemachine;


public class FSMDef {

public final static State SUBMITTED=new State("Submitted");

public final static State OPEN= new State("Open");

public final static State CANCELLED= new State("Cancelled");

public final static State CLOSED= new State("Closed");

//Events

static class Events {

public final static Event OPEN = new Event("Open");

public final static Event CLOSE = new Event("Close");

public final static Event REOPEN = new Event("Re-Open");

public final static Event CANCEL = new Event("Cancel");

}

static {

new Transition(Events.OPEN).from(SUBMITTED).to(OPEN);

new Transition(Events.CLOSE).from(OPEN).to(CLOSED);

new Transition(Events.REOPEN).from(CLOSED).to(OPEN);

new Transition(Events.CANCEL).from(OPEN).to(CANCELLED);

}

}



Doesn't seems too complex, right?
I'm just starting with this, and probably barely skim the surface (sure it has some drawbacks), but so far it worked :)

[EDIT: Fixed the generics declarations that were eaten by the HTML format. BTW, if anybody knows a good code formatter for blog posts, let me know ]