Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to create a Traversal for a List of arbitrary length #430

Open
JohnMcGuinness opened this issue Apr 8, 2021 · 1 comment
Open

How to create a Traversal for a List of arbitrary length #430

JohnMcGuinness opened this issue Apr 8, 2021 · 1 comment

Comments

@JohnMcGuinness
Copy link

JohnMcGuinness commented Apr 8, 2021

Since there's no usable documentation for this library I'll ask a question here.

I have a Cart which may have an Item in it. An Item has a Discount, which may be NoDiscount or PercentDiscount.

public record Cart(String id, Item item, int quantity)

public record Item(String sku, double price, int leftInStock, Discount discount)

sealed interface Discount permits NoDiscount, PercentDiscount

public record NoDiscount() implements Discount

public record PercentDiscount(double value) implements Discount

I have some Optics:

private static final Lens<Cart, Item> itemL = Lens.lens(Cart::item, (Item i) -> (Cart c) -> new Cart(c.id(), i, c.quantity()));

private static final Lens<Item, Discount> discountL = Lens.lens(Item::discount, d -> i -> new Item(i.sku(), i.price(), i.leftInStock(), d)); 

private static final Prism<Discount, Double> onlyPctDiscount
	= Prism.prism(
		d -> {
			if(d instanceof PercentageOff) {
				return Option.some(((PercentageOff) d).value());
			}
			else {
				return Option.none();
			}
		},
		PercentageOff::new
	);

This code recalulates the Item's Discount given a Cart:

itemL.composeLens(discountL).composePrism(onlyPctDiscount).modify(calculation).f(cart);

If I change the Cart to have a List of Item's, to recalculate the discount for each item in the cart I'm pretty sure I need to change that Prism to a Traversal.

How do I create a traversal for a list with any number of Items. From what I can make out FJ only allows Traversals for 2 to 6 items in a List.

@fourofclubs
Copy link

Creating a custom Traversal can be tricky, but there is a Traversal for Lists. It's at List.Optic.traversal().
If your Cart changes to include a List of Items, that Prism is still fine, but itemL would need to change to a Lens<Cart, List<Item>> (and probably change the name to itemsL). Then, I believe you should only need to compose an extra traversal:
itemsL.composeTraversal(List.Optic.traversal()).composeLens(discountL).composePrism(onlyPctDiscount).modify(calculation).f(cart)
That should modify each item's discount.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants