Is it a monad (in Java)?

Before I begin to claim that I nailed it, I wanted to ask. Do not hold back, please, I would like to experience any criticism first.

Since Java does not have the flexibility that dynamic languages ​​have when passing arbitrary arguments, I compensated for combining all possible inputs into one class (People), which forms the input space. Functions map this to the output space (Friends) using the monad.

I am not trying to solve the general case, I will just come up with an example to understand if I understand the design pattern.

The monad (if any) applies these rules: after rejecting an invitation or an error, there is further processing.

Sorry for the length. This is Java after all. I made a few convention labels to save space.

Is this really an example of a monad? (Encapsulated in friends class)

public class Sample {
    public static void main(String[] args) {
        People people0 = new People("Bob", "Fred");
        Friends friends0 = Friends.pipeline(people0, ToFromFunction.INVITE, ToFromFunction.ACCEPT);
        System.err.println(friends0);

        People people1 = new People("Bob", "Jenny");
        Friends friends1 = Friends.pipeline(people1, ToFromFunction.INVITE, ToFromFunction.ACCEPT);
        System.err.println(friends1);

        People people2 = new People("Bob", "Fred");
        Friends friends2 = Friends.pipeline(people2, ToFromFunction.INVITE, ToFromFunction.BLOCK);
        System.err.println(friends2);
    }
}

/** this is the space of all inputs */
public class People {
    public People(String from, String to) {
        this.from = from;
        this.to = to;
    }

    public String from;
    public String to;
}

/** this is the output space, and the monad (?) */
public class Friends {

    public boolean friends = false;
    public boolean rejected = false;
    public String errors = "";

    public static Friends unit(People from) {
        return new Friends();
    }

    public Friends bind(ToFromFunction f, People from) {
        if (! errors.isEmpty()) {
            // we have errors; skip the rest
            return this;
        }

        if (rejected) {
            // No means no
            return this;
        }

        return f.act(from, this);
    }

    public static Friends pipeline(People from, ToFromFunction... functions) {
        Friends result = Friends.unit(from);
        for (ToFromFunction f : functions) {
            result = result.bind(f, from);
        }
        return result;
    }
}

/** functions from People to Friends */
public interface ToFromFunction {

    Friends act(People from, Friends to);

    ToFromFunction INVITE = new ToFromFunction() {
        public Friends act(People from, Friends to) {
            // Jenny has blocked Bob
            if ("Jenny".equals(from.to) && "Bob".equals(from.from)) {
                to.errors = "Jenny blocked Bob";
            }
            return to;
        }
    };

    ToFromFunction ACCEPT = new ToFromFunction() {
        public Friends act(People from, Friends to) {
            // Good to go!
            to.friends = true;
            return to;
        }
    };

    ToFromFunction BLOCK = new ToFromFunction() {
        public Friends act(People from, Friends to) {
            to.friends = false;
            to.rejected = true;
            return to;
        }
    };
}
+3
source share
1 answer

Monads are types that implement two functions with a fixed signature: unit and bind.

In the Haskell notation:

unit :: a -> m a

bind :: m a -> (a -> m b) -> m b

unittransfers an object from type ato mtype a. The type amust be arbitrary. Implementation bindcan be anything (but it must satisfy monadic laws).

Try converting your example to Haskell syntax:

People are just a tuple:

type People = (String, String)

A friend type is a triplex of two Boolean elements and a string.

If we use these types, then your Friends.unit method looks something like this:

unit_friends :: People -> Friends
unit_friends _ = (false, false)

, unit_friends Friends. unit. :

unit_friends :: a -> Friends a

Java :

public static Friends<T> unit(T from) {
    // return something of type Friends<T>
}

bind ToFromFunction People - Friends:

bind_friends :: ToFromFunction -> People -> Friends

ToFromFunction

type ToFromFunction = People -> Friends -> Friends

act.

bind_friends :: (People -> Friends -> Friends) -> People -> Friends

bind_friends, - :

bind_friends :: People -> (People -> Friends -> Friends) -> Friends

:

bind_friends :: Friends a -> (a -> Friends b) -> Friends b

, .

, . bind_friends Friends, People, bind ToFromFunction Friends.

+3

All Articles