在Java 8中实现Monad

7
我正在尝试按照这篇文章中的方法在Java 8中实现Monad接口,但是我遇到了以下编译错误。

发现2个错误:

  • 文件: FunctorsMonads.java [行: 36]

    错误: FOptional不是抽象的, 并且没有覆盖Monad中的抽象方法flatMap(java.util.function.Function>)

  • 文件: FunctorsMonads.java [行: 50]

    错误: 名称冲突: FOptional中的flatMap(java.util.function.Function>)和Monad中的flatMap(java.util.function.Function)具有相同的擦除, 但都没有覆盖另一个


“Functor”接口工作得很好。非常感谢任何帮助。
这是代码:
import java.util.function.Function;

public class FunctorsMonads {

  public static void main(String[] args) {
    System.out.println(tryParse("47"));
    System.out.println(tryParse("a"));

    FOptional<String> str = FOptional.of("47");
    System.out.println(str);
    FOptional<FOptional<Integer>> num = str.map(FunctorsMonads::tryParse);
    System.out.println(num);
    FOptional<Integer> num2 = str.flatMap(FunctorsMonads::tryParse);
    System.out.println(num2);
  }

  static FOptional<Integer> tryParse(String s){
    try {
      final int i = Integer.parseInt(s);
      return FOptional.of(i);
    } catch (NumberFormatException e) {
      return FOptional.empty();
    }
  }
}

interface Functor<T, F extends Functor<?, ?>> {
  <R> F map(Function<T, R> f);
}

interface Monad<T, M extends Monad<?, ?>> extends Functor<T, M> {
  M flatMap(Function<T, M> f);
}

//class FOptional<T> implements Functor<T, FOptional<?>>
class FOptional<T> implements Monad<T, FOptional<?>> {
  private final T valueOrNull;

  private FOptional(T valueOrNull) {
    this.valueOrNull = valueOrNull;
  }

  public <R> FOptional<R> map(Function<T, R> f) {
    if (valueOrNull == null)
      return empty();
    else
      return of(f.apply(valueOrNull));
  }

  public <R> FOptional<R> flatMap(Function<T, FOptional<R>> f) {
    if (valueOrNull == null)
      return empty();
    else
      return f.apply(valueOrNull);
  }

  public static <T> FOptional<T> of(T a) {
    return new FOptional<T>(a);
  }

  public static <T> FOptional<T> empty() {
    return new FOptional<T>(null);
  }

  @Override
  public String toString() {
    return getClass().getName() + "<" + valueOrNull + ">";
  }
}

编辑:
我已在主方法中添加了以下行,作为实现正确性的试金石:
FOptional<Integer> num2 = str.flatMap(FunctorsMonads::tryParse); System.out.println(num2);


感谢@Nikolas改进了我的原始格式,并使问题更易于阅读。 - dbaltor
2个回答

6
在Java中,你无法实现完全类型安全的Monad接口。flatmap的正确签名类似于<R> M<R> flatMap(Function<T, M<R>> f),但是在Java中无法表达这个式子。这个M<R>表达式被称为高阶类型

1
已实现的方法FOptional :: flatMap 与接口Monad中的定义不匹配。
您需要做的就是修改接口Monad本身:
interface Monad<T, M extends Monad<?, ?>> extends Functor<T, M> {

    <R> M flatMap(Function<T, FOptional<R>> f);
}

此外,就我所了解的功能而言,两个接口应该以相同的精神进行设计。将新接口与Functor接口进行比较:
interface Functor<T, F extends Functor<?, ?>> {

    <R> F map(Function<T, R> f);
}

两者都定义了返回新通用类型的方法:MFMonadFunctor,并使用了一个新引入的通用类型 R

2
仅仅是 <R> M flatMap(Function<T, FOptional<R>> f);FOptional 引入了 Monad 接口的契约中,随后由 FOptional 实现。这样的方法不应该放在接口中而是应该放在实现中吗? - Naman
1
你的答案似乎是使这段代码编译的唯一可能方法。这向我展示了@MikeFHay的答案暂时是正确的。 - dbaltor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接