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

com.github.mperry.fg.Lens.groovy Maven / Gradle / Ivy

There is a newer version: 0.8
Show newest version
package com.github.mperry.fg

import fj.F
import fj.F2
import fj.P
import fj.P2
import fj.Unit
import fj.data.Either
import fj.data.Option
import groovy.transform.TypeChecked
import groovy.transform.TypeCheckingMode

/**
 * Created by MarkPerry on 14/01/14.
 */
@TypeChecked
class Lens {

    F get
    F2 set

    @TypeChecked(TypeCheckingMode.SKIP)
    static  Lens lift(F g, F2 s) {
        new Lens(g, s)
    }

    Lens(F g, F2 s) {
        get = g
        set = s
    }

    B get(A a) {
        get.f(a)
    }

    A set(A a, B b) {
        set.f(a, b)
    }

    A mod(A a, F f) {
        set(a, f.f(get(a)))
    }

    State mod(F f) {
        State.lift({ A a ->
            def b = f.f(get(a))
            P.p(set(a, b), b)
        } as F)
    }

    State mod(Closure c) {
        mod(c as F)
    }

    def  Lens andThen(Lens lens) {
        lens.compose(this)
    }

    @TypeChecked(TypeCheckingMode.SKIP)
    def  State map(F f) {
        // WARNING: this is implemented differently from
        // http://scalaz.github.io/scalaz/scalaz-2.9.1-6.0.4/doc.sxr/scalaz/Lens.scala.html
        // I have the tuple in the opposite order, i.e. P.p(a, f.f(get(a)))
        // I think this is ok as the trait States has the method "state"
        // def state[S, A](f: S => (S, A)): State[S, A] = new State[S, A] {
        // the order of the tuple returned by f is swapped compared to me
        State.lift({ A a -> P.p(a, f.f(get(a)))} as F)
    }

    def  State flatMap(F> f) {
        State.lift({ A a -> f.f(get(a)).run(a)} as F)
    }

    @TypeChecked(TypeCheckingMode.SKIP)
    def  Lens compose(Lens lens) {
        new Lens(
            Functions.o(get, lens.get),
            { C c, B b -> lens.set(c, set(lens.get(c), b)) } as F2
        )
    }

    @TypeChecked(TypeCheckingMode.SKIP)
    def  Lens, P2> product(Lens lens) {
        new Lens(
                { P2 p -> P.p(get(p._1()), lens.get(p._2())) } as F,
                { P2 ac, P2 bd -> P.p(set(ac._1(), bd._1()), lens.set(ac._2(), bd._2())) } as F2
        )
    }

    def  Lens, B> sum(Lens lens) {
        new Lens(
                { Either e ->
                    e.isLeft() ? get(e.left().value()) : lens.get(e.right().value())
                } as F,
                { Either e, B b ->
                    e.isLeft() ? Either.left(set(e.left().value(), b)) : lens.set(e.right().value(), b)
                } as F2
        )
    }

    @TypeChecked(TypeCheckingMode.SKIP)
    State update(B b) {
        State.lift({ A a ->
            P.p(set(a, b), b)
        } as F)
    }

    State update(F f) {
        update(f.f(Unit.unit()))
    }

    @TypeChecked(TypeCheckingMode.SKIP)
    State state() {
        State.lift({ A a -> P.p(a, get(a))} as F)
    }

    @TypeChecked(TypeCheckingMode.SKIP)
    static  Lens, Option> mapLens(K k) {
        new Lens(
                { Map m -> Option.fromNull(m.get(k)) } as F,
                { Map m, Option o ->
                    o.map { V v -> m + [(k): v]}.orSome(m - [k: m.get(k)])
                } as F2
        )
    }

    static  Lens, Boolean> setLens(K k) {
        new Lens(
                { Set s -> s.contains(k) } as F,
                { Set s, Boolean b ->
                    if (b) {
                        s.contains(k) ? s : ((Set) s.clone()).add(k)
                    } else {
                        s.minus(k)
                    }
                } as F2
        )

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy