Is this a monad in Java? (part 2)

My first try was on stackoverflow. I’m picking up on the answer there to improve my monad: StackOverflow – Is this a monad in Java?

My goal is to write an example of a monad. I’m not trying to solve the general case, just come up with one to see how it works. If I’m right, then I really like this pattern. I’ve already used it to rework some code I’m working on. So I hope it’s right.

I was pretty strict about the signatures & not taking shortcuts that OO allows.

The (contrived) example is to provide semantics to represent a Friend relationship between two users. If there’s an error, or the friendship is blocked, then processing stops. I have sample code that “lifts” Boolean, String and a custom Friend class into the monadic space, so I think that’ a sign I’m on the right track. I’ve included the sample code lifting String into the monadic space.

My question is, did I get the monad implementation right? Please call out the places where I jumped the rails!

public class FriendSpace<A> {

    public boolean rejected = false;
    public String errors = "";
    public A original;

    public interface Function<B, MA> {
        MA apply(B b, MA a);
    }

    public FriendSpace<A> unit(A a) {
        FriendSpace<A> that = new FriendSpace<A>();
        that.original = a;
        return that;
    }

    public <B> FriendSpace<A> bind(B b, Function<B, FriendSpace<A>> f) {
        if (! errors.isEmpty()) {
            // we have errors; skip the rest
            return this;
        }

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

        FriendSpace<A> next = f.apply(b, this);

        return next;
    }

    @SuppressWarnings("unchecked")
    public <B> FriendSpace<A> pipeline(B value,
           FriendSpace.Function<B, FriendSpace<A>>... functions) {
        FriendSpace<A> space = this;
        for (FriendSpace.Function<B, FriendSpace<A>> f : functions) {
            space = space.bind(value, f);
        }
        return space;
    }

    // toString omitted to save space
}

And here’s an example where the (arbitrary) input is a People class, and the (arbitrary) class representing the friendship state is String

public class People {

    public People(String from, String to) {
        this.from = from;
        this.to = to;
    }

    public String from;
    public String to;
}

    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        FriendSpace<String> proto = new FriendSpace<String>();

        People people0 = new People("Bob", "Fred");
        FriendSpace<String> space0 = proto.unit("");
        FriendSpace<String> friends0 = space0.pipeline(people0, VERIFY, INVITE, ACCEPT);
        System.err.println(friends0);

        People people1 = new People("Bob", "Jenny");
        FriendSpace<String> space1 = proto.unit("");
        FriendSpace<String> friends1 = space1.pipeline(people1, VERIFY, INVITE, ACCEPT);
        System.err.println(friends1);

        People people2 = new People("Fred", "Jenny");
        FriendSpace<String> space2 = proto.unit("");
        FriendSpace<String> friends2 = space2.pipeline(people2, VERIFY, INVITE, BLOCK);
        System.err.println(friends2);

        People people3 = new People("Bob", "Tom");
        FriendSpace<String> space3 = proto.unit("");
        FriendSpace<String> friends3 = space3.pipeline(people3, VERIFY, INVITE, ACCEPT);
        System.err.println(friends3);
    }

    public interface StringFunction extends FriendSpace.Function<People, FriendSpace<String>> {
    }

    static StringFunction VERIFY = new StringFunction() {
        public FriendSpace<String> apply(People from, FriendSpace<String> to) {
            String KNOWN_USERS = "Bob Fred Jenny";

            if (! KNOWN_USERS.contains(from.from)) {
                to.errors += "Unknown from: " + from.from;
            }

            if (! KNOWN_USERS.contains(from.to)) {
                to.errors += "Unknown to: " + from.to;
            }

            return to;
        }
    };

    static StringFunction INVITE = new StringFunction() {
        public FriendSpace<String> apply(People from, FriendSpace<String> to) {
            // Jenny has blocked Bob
            if ("Jenny".equals(from.to) && "Bob".equals(from.from)) {
                to.errors = "Jenny blocked Bob";
            }
            return to;
        }
    };

    static StringFunction ACCEPT = new StringFunction() {
        public FriendSpace<String> apply(People from, FriendSpace<String> to) {
            // Good to go!
            to.original = "YES";
            return to;
        }
    };

    static StringFunction BLOCK = new StringFunction() {
        public FriendSpace<String> apply(People from, FriendSpace<String> to) {
            to.original = "BLOCK";
            to.rejected = true;
            return to;
        }
    };

0

The place Java and C# fall down in implementing monads is if you bind a function a -> m b where a != b you can’t return this – you need to construct a default b to create the m b where in Haskell Nothing is a valid m b construction as well as Left anything can supplant Right anything.

You have an Either monad here which is what we OO folks prefer over Maybe because it allows us to trap some information with the issue explicitly (FP folks tend to prefer the implicit and more concise Nothing from the Maybe monad).

Fix your return this to meet the requisite polymorphism so it can take an a -> m b and return an m b even in the failure case. You’ll need to return new FriendState(something else) because this may be a FriendState<a> but your bind needs to return a FriendState<b>, right now failure only allows returning FriendState<a> which only works when you bind functions that go from a -> FriendState<a>.

I know that’s the tricky part as a C# guy who’s done variations on monads in C# myself, it’s hard to get the amount of polymorphism ADTs give you. This is a very good first crack!

3

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật