You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

验证对象是否为Monad为何需检查全部三条单子律?

单子律与违反单一条律的Monad实例

三条单子律(Java风格表述)

  • 左单位律:Monad.of(x).flatMap(y -> f(y)) 等价于 f(x)
  • 右单位律:monad.flatMap(y -> Monad.of(y)) 等价于 monad
  • 结合律:monad.flatMap(x -> f(x)).flatMap(x -> g(x)) 等价于 monad.flatMap(x -> f(x).flatMap(x -> g(x)))

下面分别给出仅违反其中一条律则、同时满足另外两条的Java实例:


1. 仅违反右单位律(用户提供的Counter实例)

代码实现

import java.util.function.Function;

class Counter<T> {
  private final T val;
  private final int count;
  
  private Counter(T val, int count) {
    this.val = val;
    this.count = count;
  }
  
  public static <T> Counter<T> of(T val) {
    return new Counter<>(val, 1);
  }
  
  public <R> Counter<R> map(Function<T, R> fn) {
    return new Counter<>(fn.apply(this.val), this.count + 1);
  }
  
  public <R> Counter<R> flatMap(Function<T, Counter<R>> fn) {
    Counter<R> tmp = fn.apply(this.val);
    return new Counter<>(tmp.val, tmp.count);
  }
  
  @Override
  public boolean equals(Object obj) {
    if (this == obj) { return true; }
    if (!(obj instanceof Counter<?>)) { return false; }
    Counter<?> ctx = (Counter<?>) obj;
    return this.val.equals(ctx.val) && this.count == ctx.count;
  }
}

律则验证

  • 满足左单位律:Counter.of(x).flatMap(f) 直接返回f(x)的结果,与f(x)完全等价。
  • 违反右单位律:若有Counter<String> c = new Counter<>("test", 3),调用c.flatMap(y -> Counter.of(y))会返回Counter.of("test")(count=1),与原实例的count=3不相等。
  • 满足结合律:两边flatMap最终都会执行f(x)获取中间实例,再执行g处理其值,返回结果的val和count完全一致。

2. 仅违反左单位律的实例

代码实现

import java.util.function.Function;
import java.util.Objects;

class LeftBrokenMonad<T> {
    private final T val;
    private final int n;

    private LeftBrokenMonad(T val, int n) {
        this.val = val;
        this.n = n;
    }

    public static <T> LeftBrokenMonad<T> of(T val) {
        return new LeftBrokenMonad<>(val, 0);
    }

    public <R> LeftBrokenMonad<R> flatMap(Function<T, LeftBrokenMonad<R>> fn) {
        LeftBrokenMonad<R> res = fn.apply(this.val);
        return new LeftBrokenMonad<>(res.val, this.n);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof LeftBrokenMonad<?>)) return false;
        LeftBrokenMonad<?> other = (LeftBrokenMonad<?>) obj;
        return Objects.equals(val, other.val) && n == other.n;
    }
}

律则验证

  • 违反左单位律:假设f(x) = new LeftBrokenMonad<>(x, 5),LeftBrokenMonad.of(x).flatMap(f)返回LeftBrokenMonad(x, 0),与f(x)的LeftBrokenMonad(x,5)不相等。
  • 满足右单位律:任意monad = new LeftBrokenMonad<>(x, 3)调用monad.flatMap(y -> LeftBrokenMonad.of(y)),会返回LeftBrokenMonad(x, 3),与原实例完全等价。
  • 满足结合律:左右两边的flatMap最终都会保留原实例的n值,仅传递val的处理结果,结果完全一致。

3. 仅违反结合律的实例

代码实现

import java.util.function.Function;
import java.util.Objects;

enum Dir {
    E, A, B;

    public Dir multiply(Dir other) {
        if (this == E) return other;
        if (other == E) return this;
        if (this == A) {
            return other == A ? E : A;
        }
        return other == A ? B : E;
    }
}

class AssociativeBrokenMonad<T> {
    private final T val;
    private final Dir dir;

    private AssociativeBrokenMonad(T val, Dir dir) {
        this.val = val;
        this.dir = dir;
    }

    public static <T> AssociativeBrokenMonad<T> of(T val) {
        return new AssociativeBrokenMonad<>(val, Dir.E);
    }

    public <R> AssociativeBrokenMonad<R> flatMap(Function<T, AssociativeBrokenMonad<R>> fn) {
        AssociativeBrokenMonad<R> res = fn.apply(this.val);
        return new AssociativeBrokenMonad<>(res.val, this.dir.multiply(res.dir));
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof AssociativeBrokenMonad<?>)) return false;
        AssociativeBrokenMonad<?> other = (AssociativeBrokenMonad<?>) obj;
        return Objects.equals(val, other.val) && dir == other.dir;
    }
}

律则验证

  • 满足左单位律:of(x).flatMap(f)会返回(E * res.dir, res.val),与f(x)的(res.dir, res.val)完全等价。
  • 满足右单位律:任意monad调用monad.flatMap(y -> of(y)),会返回(s * E, x),与原实例(s,x)完全等价。
  • 违反结合律:取monad = new AssociativeBrokenMonad<>("test", Dir.A),f(x) = new AssociativeBrokenMonad<>(x, Dir.B),g(x) = new AssociativeBrokenMonad<>(x, Dir.A):
    • 左边:monad.flatMap(f).flatMap(g)最终返回(E, "test")
    • 右边:monad.flatMap(x -> f(x).flatMap(g))最终返回(A, "test")
      两者结果不相等,违反结合律。

内容的提问来源于stack exchange,提问作者teckorjanin7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 05:40:26