Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@
<version>1.0-SNAPSHOT</version>


<dependencies>
<dependency>
<groupId>org.derive4j</groupId>
<artifactId>derive4j</artifactId>
<version>0.7</version>
<!-- compile-only dependency (not used at runtime): -->
<optional>true</optional>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,12 @@
import java.util.Map;
import java.util.function.Function;

public class VisitorLambda {

public static class LambdaVisitor<A> implements Function<Object, A> {
private Map<Class<?>, Function<Object, A>> fMap = new HashMap<>();

public <B> Acceptor<A, B> on(Class<B> clazz) {
return new Acceptor<>(this, clazz);
}

@Override
public A apply( Object o ) {
return fMap.get(o.getClass()).apply( o );
}

static class Acceptor<A, B> {
private final LambdaVisitor visitor;
private final Class<B> clazz;
import static org.mfusco.fromgoftolambda.examples.visitor.Elements.circleElement;
import static org.mfusco.fromgoftolambda.examples.visitor.Elements.rectangleElement;
import static org.mfusco.fromgoftolambda.examples.visitor.Elements.squareElement;

public Acceptor( LambdaVisitor<A> visitor, Class<B> clazz ) {
this.visitor = visitor;
this.clazz = clazz;
}
public class VisitorLambda {

public LambdaVisitor<A> then(Function<B, A> f) {
visitor.fMap.put( clazz, f );
return visitor;
}
}
}

public static class Square {
final double side;
Expand Down Expand Up @@ -62,18 +39,32 @@ public Rectangle( double weidht, double height ) {
}
}

static Function<Object, Double> areaVisitor = new LambdaVisitor<Double>()
.on(Square.class).then( s -> s.side * s.side )
.on(Circle.class).then( c -> Math.PI * c.radius * c.radius )
.on(Rectangle.class).then( r -> r.height * r.weidht );
@org.derive4j.Data
// see the generated "Elements" class for constructors (https://gist.github.com/jbgi/393f621decdeb1374b1f3356b2d140b6)
interface Element {
// we could have used the same visitor interface as in gof visitor... but let's go with an equivalent catamorphism definition:
<T> T match( Function<Square, T> squareElement,
Function<Circle, T> circleElement,
Function<Rectangle, T> rectangleElement );
}


// like with the visitor pattern, pattern matching synthax ensure that all 3 cases are handled:

static Function<Element, Double> areaVisitor = element -> element.match(
s -> s.side * s.side,
c -> Math.PI * c.radius * c.radius,
r -> r.height * r.weidht
);

static Function<Object, Double> perimeterVisitor = new LambdaVisitor<Double>()
.on(Square.class).then( s -> 4 * s.side )
.on(Circle.class).then( c -> 2 * Math.PI * c.radius )
.on(Rectangle.class).then( r -> 2 * r.height + 2 * r.weidht );
// or using the equivalent syntax generated by derive4j:
static Function<Element, Double> perimeterVisitor = Elements.cases()
.squareElement( s -> 4 * s.side )
.circleElement( c -> 2 * Math.PI * c.radius )
.rectangleElement( r -> 2 * r.height + 2 * r.weidht );

public static void main( String[] args ) {
List<Object> figures = Arrays.asList( new Circle( 4 ), new Square( 5 ), new Rectangle( 6, 7 ) );
List<Element> figures = Arrays.asList( circleElement(new Circle( 4 )), squareElement(new Square( 5 )), rectangleElement(new Rectangle( 6, 7 )) );

double totalArea = figures.stream().map( areaVisitor ).reduce( 0.0, (v1, v2) -> v1 + v2 );
System.out.println("Total area = " + totalArea);
Expand Down