package com.github.rfqu.so;
import java.util.Random;
/**
* To illustrate discussion at
* http://stackoverflow.com/questions/13080042/the-right-way-to-make-java-function-objects-to-encapsulate-generic-functions
* Author: Alexei Kaigorodov
*/
public class SoFun {
static interface Unary<E,R> {
R ap(E a) ;
}
static interface Binary<E,R> {
R ap(E a, E b) ;
}
static interface Group<E> {
E plus(E op1,E op2);
}
static interface Applier {
<E> E ap (Group<E> gp, E x, E y);
}
static class PlusApplier implements Applier {
@Override
public <E> E ap(Group<E> gp, E x, E y) {
return gp.plus(x, y);
}
}
static class Rational {
int x, y; // x/y
public Rational(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if (obj==null) return false;
if (!(obj instanceof Rational)) return false;
Rational other=(Rational)obj;
return x*other.y==y*other.x;
}
}
static class Integers implements Group<Integer> {
@Override
public Integer plus(Integer op1, Integer op2) {
return op1+op2;
}
}
static class Rationals implements Group<Rational> {
@Override
public Rational plus(Rational op1, Rational op2) {
return new Rational(op1.x*op2.y+op1.y*op2.x, op1.y*op2.y);
}
}
static class F implements Unary<Integer, Rational> {
public Rational ap (Integer x) { return new Rational(x,2); }
}
static class IntPlus implements Binary<Integer, Integer> {
public Integer ap(Integer a, Integer b) { return a+b; }
}
static class IntEq implements Binary<Integer, Boolean> {
public Boolean ap(Integer a, Integer b) { return a.equals(b); }
}
static class RatEq implements Binary<Rational, Boolean> {
public Boolean ap(Rational a, Rational b) { return a.equals(b); }
}
static <E,R> boolean checkCommutesWith(
Unary<E,R> f
, Applier g
, Binary<R,Boolean> eq
, Group<E> domain, Group<R> range
, E x, E y)
{
E g_ap1 = g.ap(domain, x, y);
R f_ap_x = f.ap(x), f_ap_y = f.ap(y);
R g_ap2 = g.ap(range, f_ap_x, f_ap_y);
return eq.ap( f.ap(g_ap1), g_ap2);
}
public static void main(String[] args) {
Random rand=new Random();
boolean res = checkCommutesWith(new F(), new PlusApplier(), new RatEq(),
new Integers(), new Rationals(), rand.nextInt(), rand.nextInt());
System.out.println("res="+res);
}
}