在我到处声称我已经钉了它之前,我想问一下。请不要退缩,我想先在这里遇到任何批评。
由于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;
}
};
}
答案 0 :(得分:3)
Monads是Types,它实现了两个带有固定签名的函数:unit和bind。
在Haskell表示法中:
unit :: a -> m a
bind :: m a -> (a -> m b) -> m b
unit
将a
类型的对象包装为m
类型的a
。 a
的类型必须是任意的。 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。