All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jnape.palatable.lambda.lens.lenses.ListLens Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
package com.jnape.palatable.lambda.lens.lenses;

import com.jnape.palatable.lambda.adt.Maybe;
import com.jnape.palatable.lambda.lens.Lens;

import java.util.ArrayList;
import java.util.List;

import static com.jnape.palatable.lambda.adt.Maybe.maybe;
import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take;
import static com.jnape.palatable.lambda.lens.Lens.simpleLens;
import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftA;
import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftB;
import static java.lang.Math.abs;

/**
 * Lenses that operate on {@link List}s.
 */
public final class ListLens {

    private ListLens() {
    }

    /**
     * Convenience static factory method for creating a lens over a copy of a list. Useful for composition to avoid
     * mutating a list reference.
     *
     * @param  the list element type
     * @return a lens that focuses on copies of lists
     */
    public static  Lens.Simple, List> asCopy() {
        return simpleLens(ArrayList::new, (xs, ys) -> ys);
    }

    /**
     * Convenience static factory method for creating a lens that focuses on an element in a list at a particular index.
     * Wraps result in a {@link Maybe} to handle null values or indexes that fall outside of list boundaries.
     *
     * @param index the index to focus on
     * @param    the list element type
     * @return Maybe the element at the index
     */
    public static  Lens.Simple, Maybe> elementAt(int index) {
        return simpleLens(xs -> maybe(xs.size() > index ? xs.get(index) : null),
                          (xs, maybeX) -> {
                              List updated = new ArrayList<>(xs);
                              return maybeX.fmap(x -> {
                                  int minimumSize = index + 1;
                                  if (minimumSize > xs.size()) {
                                      take(abs(updated.size() - minimumSize), repeat((X) null)).forEach(updated::add);
                                  }
                                  updated.set(index, x);
                                  return updated;
                              }).orElseGet(() -> {
                                  if (updated.size() > index) {
                                      updated.set(index, null);
                                  }
                                  return updated;
                              });
                          });
    }

    /**
     * Convenience static factory method for creating a lens that focuses on an element in a list at a particular index,
     * returning defaultValue if there is no value at that index.
     * 

* Note that this lens is NOT lawful, since "putting back what you got changes nothing" fails for any value * B where S is the empty list * * @param index the index to focus on * @param defaultValue the value to use if there is no element at index * @param the list element type * @return the element at the index, or defaultValue */ @SuppressWarnings("unchecked") public static Lens.Simple, X> elementAt(int index, X defaultValue) { return unLiftB(unLiftA(elementAt(index), defaultValue))::apply; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy