Introduction
As shown in previous posts, I really like F# Active Patterns and Scala Extractors. Among other things these features allows to create multiple pattern matching representations of objects . One of the ideas behind these concepts is "Views" presented by Philip Wadler in the Views: A way for pattern matching to cohabit with data abstraction paper.
It is possible to use Tom object mappings(explained here) to get a similar effect.
Example
For this example, an alternative representation for a Complex number will be created. A complex number could be represented by Cartesian coordinates (real and imaginary parts) and by Polar coordinates (angle and modulus).
This example is used to present Views, Extractors and Active Patterns.
The Apache Commons Complex class will be used as the complex number implementation.
First, a mapping for the Complex sort needs to be created.
%include { double.tom }
%typeterm Complex {
implement { org.apache.commons.math.complex.Complex }
is_sort(t) { t instanceof org.apache.commons.math.complex.Complex }
equals(t1,t2) { t1.equals(t2) }
}
Then, a mapping for the Complex number with Cartesian coordinates is created. Since the Complex class is in Cartesian coordinates only the
getReal
and getImaginary
accessors are required.
%op Complex Complex(real:double,img :double ) {
is_fsym(t) { t instanceof org.apache.commons.math.complex.Complex }
get_slot(real, t) { t.getReal() }
get_slot(img, t) { t.getImaginary() }
make(real,img) { new org.apache.commons.math.complex.Complex(real,img) }
}
Finally a mapping for the Polar representation. Since the Complex class stores the number in Cartesian coordinates a conversion must be applied to get the angle and modulus slots. Also the polar2Complex method is used to create a
Complex
instance using the Polar
symbol.
%op Complex Polar(m:double,a :double ) {
is_fsym(t) { t instanceof org.apache.commons.math.complex.Complex }
get_slot(a, t) { Math.atan2(t.getImaginary(), t.getReal()) }
get_slot(m, t) {
Math.sqrt(t.getReal() * t.getReal() +
t.getImaginary() * t.getImaginary()) }
make(radial,modulus) {
org.apache.commons.math.complex.ComplexUtils.polar2Complex(
radial,
modulus) }
}
A use of these mappings is the following:
Complex c = new Complex(3,3);
%match(c) {
Polar(m,a) -> {
System.out.println(
String.format("%f,%f",`m,`a ));
}
}
Also given that a
make
declaration was added to the mappings we can use the object creation syntax as follows:
Complex c2 = `Polar(3,Math.PI/2.0);
%match ( c2){
Complex(r,i) -> {
System.out.println(
String.format("%f,%f",`r,`i));
}
}