【问题标题】:Is this a monad (in Java)?这是一个单子(Java)吗?
【发布时间】:2014-02-08 06:19:52
【问题描述】:

在我四处声称我已经成功之前,我想问一下。请不要退缩,我想先在这里体验任何批评。

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

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

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

抱歉,篇幅较长。毕竟是Java。为了节省空间,我采用了一些约定俗成的捷径。

这实际上是一个单子的例子吗? (封装在 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;
        }
    };
}

【问题讨论】:

  • 你在@BrianGordon 有什么收获?这些是针对程序员的主题指南,而不是 Stack Overflow。
  • @Makoto 对不起,我是说这对程序员来说是一个合适的问题。它不适合 StackOverflow。
  • 真正的问题是什么?
  • "这实际上是一个单子的例子吗?" ——原来的帖子最后有点落后了。编辑澄清这一点,谢谢!

标签: java monads


【解决方案1】:

Monad 是类型,它实现了两个具有固定签名的函数:单元和绑定。

在 Haskell 表示法中:

unit :: a -> m a

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

unita 类型的对象包装到 a 类型的 m 中。 a 的类型必须是任意的。 bind 的实现可以是任何东西(但它必须满足一元法则)。

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

人只是一个元组:

type People = (String, String)

Friends 的类型是两个布尔值和一个字符串的三元组。

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

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

这意味着,unit_friends 正在丢弃 is 参数并仅返回 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。

【讨论】:

  • 所以这比我想象的还要抽象,我可以看到 Java 中的强类型是一个障碍。但我喜欢几乎单子的灵活性;我有兴趣看看更接近的版本是如何工作的。再次感谢您查看。
  • 仅供参考,我添加了您的输入并再次破解programmers.stackexchange.com/questions/229135/… ...我想这次我得到了正确的签名。
猜你喜欢
  • 1970-01-01
  • 2011-06-30
  • 1970-01-01
  • 1970-01-01
  • 2013-03-14
  • 2012-05-16
  • 1970-01-01
  • 2013-07-04
相关资源
最近更新 更多