【问题标题】:Java 8 Generic of Generic for Monad Transformer用于 Monad Transformer 的 Java 8 泛型
【发布时间】:2015-11-10 17:55:39
【问题描述】:

我正在使用“完全懒惰”并且我希望在我正在编写的程序中使用Either<String,Option<A>>。这是一个使用 Monad Transformer for Option 的好地方(类似于 Scalaz 7 中的真棒)。我似乎无法在 Java 8 中正确使用泛型。下面的代码是我希望它看起来的样子(作为开始)。任何关于如何让它工作/编译的建议都会很棒!!!请帮助我让这个 Monad Transformer 存在于我的 Java 8 代码中。

import com.googlecode.totallylazy.Monad;
import com.googlecode.totallylazy.Option;
import com.googlecode.totallylazy.functions.Function1;
import static com.google.common.base.Preconditions.checkNotNull;

public class OptionT<M extends Monad,A> {
   final M<Option<A>> run;

   public OptionT(final M<Option<A>> run){
       this.run = checkNotNull(run);
   }

   public <B> OptionT<M,B> map(Function1<A,B> f){
       return new OptionT<M,B>(run.map(o-> o.map(f)));
   }
}

编辑:我得到以下编译器故障:

OptionT.java:15: error: unexpected type
    final M<A> run;
          ^
  required: class
  found:    type parameter M
  where M is a type-variable:
    M extends Monad<Option<?>> declared in class OptionT
OptionT.java:17: error: unexpected type
    public OptionT(final M<A> run){
                         ^
  required: class
  found:    type parameter M
  where M is a type-variable:
    M extends Monad<Option<?>> declared in class OptionT

【问题讨论】:

  • 怎么不工作?
  • 您不能将泛型参数传递给 Java 中的泛型参数(M&lt;?&gt;,其中 M 是泛型)。这不会直接从 Scala 翻译过来;它们是截然不同的语言。
  • Java 的类型系统不支持更高种类的类型。你不能这样做。
  • 有没有办法“解决”这个限制? &lt;M extends Monad&lt;Option&lt;A&gt;&gt;,A&gt; 之类的东西?我尝试了类似的方法,但不能保证Mmap 的类型签名中保持不变。 :(
  • 我的猜测是,无论你想出什么都将是丑陋和冗长的,以至于没有用处(与非单调地做相比)。 Java 并不是为这种高度功能化的编码风格而设计的。它可以很好地完成简单的事情(映射、基本转换等),但是当您进入 FP 的类型系统方面(monads、currying 等)时,它开始看起来越来越像面向对象编程,即它到底是什么。

标签: java generics functional-programming java-8 monad-transformers


【解决方案1】:

您可以使用cyclops-monad-api 进行此操作,有一个介绍性的blog post that you might find helpful here。我是图书馆和博客文章的作者。

我已经在下面发布了您的示例(适用于 JDK 8 Optional)的工作实现 -

public class OptionT<A> {
   @Getter
   final AnyM<Optional<A>> run;

   public OptionT(final AnyM<Optional<A>> run){
       this.run = run;
   }

   public <B> OptionT<B> map(Function<A,B> f){
       return new OptionT<B>(run.map(o-> o.map(f)));
   }


}

@Test
public void test() {
    OptionT<Integer> optionT = new OptionT<>(AnyM.ofMonad(Stream.of(Optional.of(10))));
    System.out.println(optionT.map(num->"hello world"+num).getRun().asSequence().firstValue());
}

会打印出来

Optional[hello world10]

AnyM 包装任何 Monad 类型。 Java 不支持 Higher-Kinded-Types,因此您不能将泛型放在泛型上。但是,您可以将 monad 类型包装在通用 API 后面,这就是 AnyM 所做的。

如果有人对 cyclops-monad-api 感兴趣,现在 Monad Transformers 的范围越来越大,受到这个问题的启发 - 感谢 OP!

【讨论】:

    【解决方案2】:

    github上有一个项目https://github.com/DanielGronau/highj,它试图克服java缺乏更高种类的类型。

    但您也可以省心并使用具有适当更高种类类型的函数式编程语言,例如https://github.com/Frege/frege

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-12
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 2011-01-06
      相关资源
      最近更新 更多