Skip to content

Instantly share code, notes, and snippets.

@rhyskeepence
Created September 6, 2012 13:15
Show Gist options
  • Save rhyskeepence/3656131 to your computer and use it in GitHub Desktop.
Save rhyskeepence/3656131 to your computer and use it in GitHub Desktop.
Lenses in Java/TotallyLazy
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);
}
});
}
}
);
}
}
@rhyskeepence
Copy link
Author

package rhyskeepence

import scalaz._

object Lenses extends App {

  val rhys = Person("Rhys", 33, Place("2 east lane", Postcode("SE16", "4UQ")))

  val ageLens = Lens.lensu(
    set = (p: Person, newAge: Int) => p.copy(age = newAge),
    get = (x: Person) => x.age)

  val olderRhys = ageLens.set(rhys, 34)
  println(olderRhys)

  val placeLens = Lens.lensu(
    set = (person: Person, place: Place) => person.copy(place = place),
    get = (person: Person) => person.place)

  val postcodeLens = Lens.lensu(
    set = (p: Place, postcode: Postcode) => p.copy(postcode = postcode),
    get = (p: Place) => p.postcode)

  val personPostcode = placeLens andThen postcodeLens

  val rhysMoved = personPostcode.set(rhys, Postcode("E1", "1AA"))
  println(rhysMoved)
}

case class Person(name: String, age: Int, place: Place)
case class Place(address: String, postcode: Postcode)
case class Postcode(outward: String, inward: String)

@raymanoz
Copy link

raymanoz commented Sep 9, 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);
            }
        };
    }
}

}

@raymanoz
Copy link

raymanoz commented Sep 9, 2012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment