Created
September 6, 2012 13:15
-
-
Save rhyskeepence/3656131 to your computer and use it in GitHub Desktop.
Lenses in Java/TotallyLazy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.googlecode.totallylazy.Callable1; | |
import com.googlecode.totallylazy.Callable2; | |
public class Lenses { | |
public static void main(String[] args) throws Exception { | |
Person rhys = new Person("rhys", 33, new Address("2 east lane", new Postcode("se16", "4uq"))); | |
Person older_rhys = personAgeLens().set(rhys, 34); | |
System.out.println(older_rhys); | |
Lens<Person, Postcode> personPostcodeLens = personAddressLens().andThen(addressPostcodeLens()); | |
Person rhys_at_e1 = personPostcodeLens.set(rhys, new Postcode("e1", "1aa")); | |
System.out.println(rhys_at_e1); | |
} | |
private static Lens<Person, Integer> personAgeLens() { | |
return Lens.lens(new Callable1<Person, Integer>() { | |
public Integer call(Person person) throws Exception { | |
return person.age; | |
} | |
}, new Callable2<Person, Integer, Person>() { | |
public Person call(Person person, Integer newAge) throws Exception { | |
return new Person(person.name, newAge, person.address); | |
} | |
} | |
); | |
} | |
private static Lens<Address, Postcode> addressPostcodeLens() { | |
return Lens.lens(new Callable1<Address, Postcode>() { | |
public Postcode call(Address address) throws Exception { | |
return address.postcode; | |
} | |
}, new Callable2<Address, Postcode, Address>() { | |
public Address call(Address address, Postcode newPostcode) throws Exception { | |
return new Address(address.street, newPostcode); | |
} | |
} | |
); | |
} | |
private static Lens<Person, Address> personAddressLens() { | |
return Lens.lens(new Callable1<Person, Address>() { | |
public Address call(Person person) throws Exception { | |
return person.address; | |
} | |
}, new Callable2<Person, Address, Person>() { | |
@Override | |
public Person call(Person person, Address newAddress) throws Exception { | |
return new Person(person.name, person.age, newAddress); | |
} | |
} | |
); | |
} | |
} | |
class Person { | |
final String name; | |
final int age; | |
final Address address; | |
Person(String name, int age, Address address) { | |
this.name = name; | |
this.age = age; | |
this.address = address; | |
} | |
public String toString() { | |
return name + ": age=" + age + ", address=" + address; | |
} | |
} | |
class Address { | |
final String street; | |
final Postcode postcode; | |
Address(String street, Postcode postcode) { | |
this.street = street; | |
this.postcode = postcode; | |
} | |
public String toString() { | |
return street + " " + postcode; | |
} | |
} | |
class Postcode { | |
final String outward; | |
final String inward; | |
Postcode(String outward, String inward) { | |
this.outward = outward; | |
this.inward = inward; | |
} | |
public String toString() { | |
return outward + " " + inward; | |
} | |
} | |
class Lens<SRC, VIEW> implements Callable1<SRC, VIEW> { | |
private final Callable1<SRC, VIEW> get; | |
private final Callable2<SRC, VIEW, SRC> set; | |
public Lens(Callable1<SRC, VIEW> get, Callable2<SRC, VIEW, SRC> set) { | |
this.get = get; | |
this.set = set; | |
} | |
public static <A, B> Lens<A, B> lens(Callable1<A, B> getFunction, Callable2<A, B, A> setFunction) { | |
return new Lens<A, B>(getFunction, setFunction); | |
} | |
public VIEW get(SRC whole) throws Exception { | |
return get.call(whole); | |
} | |
public SRC set(SRC whole, VIEW newValue) throws Exception { | |
return set.call(whole, newValue); | |
} | |
public VIEW call(SRC whole) throws Exception { | |
return get(whole); | |
} | |
public SRC mod(SRC whole, Callable1<VIEW, VIEW> updateFunction) throws Exception { | |
return set(whole, updateFunction.call(get(whole))); | |
} | |
public <SUBVIEW> Lens<SRC, SUBVIEW> andThen(final Lens<VIEW, SUBVIEW> other) { | |
return other.compose(this); | |
} | |
public <SUBVIEW> Lens<SUBVIEW, VIEW> compose(final Lens<SUBVIEW, SRC> other) { | |
return new Lens<SUBVIEW, VIEW>(new Callable1<SUBVIEW, VIEW>() { | |
public VIEW call(SUBVIEW otherPart) throws Exception { | |
return get(other.get(otherPart)); | |
} | |
}, new Callable2<SUBVIEW, VIEW, SUBVIEW>() { | |
public SUBVIEW call(final SUBVIEW otherPart, final VIEW part) throws Exception { | |
return other.mod(otherPart, new Callable1<SRC, SRC>() { | |
public SRC call(SRC a) throws Exception { | |
return set(a, part); | |
} | |
}); | |
} | |
} | |
); | |
} | |
} |
Author
rhyskeepence
commented
Sep 6, 2012
Some stylistic changes on Java version, and use of function composition for lens get().
package com.example;
import com.googlecode.totallylazy.Function1;
import com.googlecode.totallylazy.Function2;
public class Lenses {
public static void main(String[] args) throws Exception {
Person rhys = new Person("rhys", 33, new Address("2 east lane", new Postcode("se16", "4uq")));
Person older_rhys = Person.lenses.age.set(rhys, 34);
System.out.println(older_rhys);
Person rhys_at_e1 = Person.lenses.postcode.set(rhys, new Postcode("e1", "1aa"));
System.out.println(rhys_at_e1);
}
}
class Person {
final String name;
final int age;
final Address address;
Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String toString() {
return name + ": age=" + age + ", address=" + address;
}
public static class lenses {
public static final Lens<Person,Integer> age = Lens.lens(functions.age, functions.setAge);
public static final Lens<Person,Address> address = Lens.lens(functions.address, functions.setAddress);
public static final Lens<Person, Postcode> postcode = address.andThen(Address.lenses.postcode);
}
public static class functions {
public static final Function1<Person, Integer> age = new Function1<Person, Integer>() {
public Integer call(Person person) throws Exception {
return person.age;
}
};
public static final Function2<Person, Integer, Person> setAge = new Function2<Person, Integer, Person>() {
public Person call(Person person, Integer newAge) throws Exception {
return new Person(person.name, newAge, person.address);
}
};
public static final Function1<Person, Address> address = new Function1<Person, Address>() {
public Address call(Person person) throws Exception {
return person.address;
}
};
public static final Function2<Person, Address, Person> setAddress = new Function2<Person, Address, Person>() {
public Person call(Person person, Address newAddress) throws Exception {
return new Person(person.name, person.age, newAddress);
}
};
}
}
class Address {
final String street;
final Postcode postcode;
Address(String street, Postcode postcode) {
this.street = street;
this.postcode = postcode;
}
public String toString() {
return street + " " + postcode;
}
public static class lenses {
public static final Lens<Address,Postcode> postcode = Lens.lens(functions.postcode, functions.setPostcode);
}
public static class functions {
public static final Function1<Address, Postcode> postcode = new Function1<Address, Postcode>() {
public Postcode call(Address address) throws Exception {
return address.postcode;
}
};
public static final Function2<Address, Postcode, Address> setPostcode = new Function2<Address, Postcode, Address>() {
public Address call(Address address, Postcode newPostcode) throws Exception {
return new Address(address.street, newPostcode);
}
};
}
}
class Postcode {
final String outward;
final String inward;
Postcode(String outward, String inward) {
this.outward = outward;
this.inward = inward;
}
public String toString() {
return outward + " " + inward;
}
}
class Lens<SRC, VIEW> extends Function1<SRC, VIEW> {
private final Function1<SRC, VIEW> get;
private final Function2<SRC, VIEW, SRC> set;
public Lens(Function1<SRC, VIEW> get, Function2<SRC, VIEW, SRC> set) {
this.get = get;
this.set = set;
}
public static <A, B> Lens<A, B> lens(Function1<A, B> getFunction, Function2<A, B, A> setFunction) {
return new Lens<A, B>(getFunction, setFunction);
}
public VIEW get(SRC whole) throws Exception {
return get.call(whole);
}
public SRC set(SRC whole, VIEW newValue) throws Exception {
return set.call(whole, newValue);
}
public VIEW call(SRC whole) throws Exception {
return get(whole);
}
public SRC mod(SRC whole, Function1<VIEW, VIEW> updateFunction) throws Exception {
return set(whole, updateFunction.call(get(whole)));
}
public <SUBVIEW> Lens<SRC, SUBVIEW> andThen(final Lens<VIEW, SUBVIEW> other) {
return other.compose(this);
}
public <SUBVIEW> Lens<SUBVIEW, VIEW> compose(final Lens<SUBVIEW, SRC> other) {
return new Lens<SUBVIEW, VIEW>(functions.get(other).then(functions.get(this)),
new Function2<SUBVIEW, VIEW, SUBVIEW>() {
public SUBVIEW call(final SUBVIEW otherPart, final VIEW part) throws Exception {
return other.mod(otherPart, new Function1<SRC, SRC>() {
public SRC call(SRC a) throws Exception {
return set(a, part);
}
});
}
}
);
}
public static class functions {
public static <SRC, VIEW> Function1<SRC, VIEW> get(final Lens<SRC, VIEW> lens) {
return new Function1<SRC, VIEW>() {
public VIEW call(SRC src) throws Exception {
return lens.get(src);
}
};
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment