这是一个monad(在Java中)吗?

时间:2014-02-08 06:19:52

标签: java monads

在我到处声称我已经钉了它之前,我想问一下。请不要退缩,我想先在这里遇到任何批评。

由于Java缺乏动态语言传递任意参数的灵活性,我通过将所有可能的输入捆绑到一个类(People)来补偿,这些类形成了输入空间。这些函数在monad的帮助下将其映射到输出空间(Friends)。

我不是要解决一般情况,只想出一个例子来看我是否理解设计模式。

monad(如果是这样)执行这些规则:一旦邀请被拒绝,或者有错误,就没有进一步的处理。

抱歉这个长度。毕竟它是Java。我采用了常规的快捷方式来节省空间。

这实际上是monad的一个例子吗? (封装在Friends类中)

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;
        }
    };
}

1 个答案:

答案 0 :(得分:3)

Monads是Types,它实现了两个带有固定签名的函数:unit和bind。

在Haskell表示法中:

unit :: a -> m a

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

unita类型的对象包装为m类型的aa的类型必须是任意的。 bind的实施可以是任何事情(但必须满足一元法则)。

让我们尝试将您的示例转换为Haskell语法:

人只是一个元组:

type People = (String, String)

朋友的类型是两个布尔值和一个字符串的小部件。

如果我们使用这些类型,那么Friends.unit方法就是这样的:

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的参数,因为lambda函数应该是第二个参数:

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

但它有这种类型的签名:

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

你的单位和绑定类型与真正的monad不匹配,但它有点接近。

让我们忘记片刻,我们需要任意类型a。 bind_friends的第一个参数必须是Friends类型,而不是People类型,因为bind应该将ToFromFunction提升到Friends monad。