Skip to content

Instantly share code, notes, and snippets.

@dtchepak
Created August 3, 2012 07:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dtchepak/3245278 to your computer and use it in GitHub Desktop.
Save dtchepak/3245278 to your computer and use it in GitHub Desktop.
Attempt at lens in c#
public class Lens<T, TValue>
{
public Func<T, TValue> Get { get; private set; }
public Func<TValue, T, T> Set { get; private set; }
public Lens(Func<T, TValue> get, Func<TValue, T, T> set)
{
Get = get;
Set = set;
}
public T Modify(Func<TValue, TValue> updateValue, T original)
{
var newValue = updateValue(Get(original));
return Set(newValue, original);
}
public Lens<T1, TValue> Compose<T1>(Lens<T1, T> lens)
{
return new Lens<T1, TValue>(
t1 => Get(lens.Get(t1)),
(value, t1) =>
{
var t = lens.Get(t1);
return lens.Set(Set(value, t), t1);
}
);
}
public class Address
{
public Address(int number, string street, State state) { Number = number; Street = street; State = state; }
public int Number { get; private set; }
public string Street { get; private set; }
public State State { get; private set; }
}
public class State
{
public State(string name) { Name = name; }
public string Name { get; private set; }
}
public readonly static Lens<State, string> StateNameLens
= new Lens<State, string>(x => x.Name, (value, x) => new State(value));
public readonly static Lens<Address, int> AddressNumberLens
= new Lens<Address, int>(x => x.Number, (value, x) => new Address(value, x.Street, x.State));
public readonly static Lens<Address, string> AddressStreetLens
= new Lens<Address, string>(x => x.Street, (value, x) => new Address(x.Number, value, x.State));
public readonly static Lens<Address, State> AddressStateLens
= new Lens<Address, State>(x => x.State, (value, x) => new Address(x.Number, x.Street, value));
[Test]
public void UpdateOneProperty()
{
var state = new State("NSW");
var result = StateNameLens.Modify(x => "VIC", state);
result.Name.ShouldBe("VIC");
}
[Test]
public void ComposeUpdate()
{
var address = new Address(1, "First St", new State("NSW"));
var addressStateLens = StateNameLens.Compose(AddressStateLens);
var updatedAddress = addressStateLens.Set("VIC", address);
updatedAddress.Number.ShouldBe(address.Number);
updatedAddress.Street.ShouldBe(address.Street);
updatedAddress.State.Name.ShouldBe("VIC");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment