带有 Java 8 的 Monads

2022-08-31 11:49:59

为了帮助理解monad是什么,有人可以提供一个使用java的例子吗?他们可能吗?

如果您从这里下载与 lambda 兼容的预发布 JDK8,则可以使用 java 来使用 lambda 表达式 http://jdk8.java.net/lambda/

下面显示了使用此JDK的lambda的示例,有人可以提供一个相对简单的monad吗?

public interface TransformService {
        int[] transform(List<Integer> inputs);
    }
    public static void main(String ars[]) {
        TransformService transformService = (inputs) -> {
            int[] ints = new int[inputs.size()];
            int i = 0;
            for (Integer element : inputs) {
                ints[i] = element;
            }
            return ints;
        };

        List<Integer> inputs = new ArrayList<Integer>(5) {{
            add(10);
            add(10);
        }};
        int[] results = transformService.transform(inputs);
    }

答案 1

仅供参考:

提议的JDK8 Optional确实满足个Monad定律。这里有一个要点来证明这一点。

要成为一个Monad,所需要的只是提供个符合个定律的功能。

这两个函数:

  1. 值放入一元上下文

    • 哈斯克尔的也许:return / Just
    • Scala的选择:Some
    • 函数式Java的选项:Option.some
    • JDK8 的可选:Optional.of
  2. 在一元上下文中应用函数

    • Haskell's Maybe: (aka>>=bind)
    • Scala的选择:flatMap
    • 函数式Java的选项:flatMap
    • JDK8 的可选:flatMap

请参阅上面的要点,了解三个定律的java演示。

注意:要了解的关键事项之一是要在 monadic 上下文中应用的函数的签名:它采用 raw 值类型,并返回 monadic 类型。

换句话说,如果你有一个实例,你可以传递给它的方法的函数将具有签名,其中是一个不必是的值类型,例如:Optional<Integer>flatMap(Integer) -> Optional<U>UIntegerString

Optional<Integer> maybeInteger = Optional.of(1);

// Function that takes Integer and returns Optional<Integer>
Optional<Integer> maybePlusOne = maybeInteger.flatMap(n -> Optional.of(n + 1));

// Function that takes Integer and returns Optional<String>
Optional<String> maybeString = maybePlusOne.flatMap(n -> Optional.of(n.toString));

你不需要任何类型的Monad接口来以这种方式编码,或者以这种方式思考。在Scala中,你不会编码到Monad接口(除非你使用的是Scalaz库...)。看起来JDK8将使Java人员也能够使用这种风格的链式一元计算

希望这是有帮助的!

更新:在这里写博客。


答案 2

Java 8 将有 lambdas;monads是一个完全不同的故事。它们很难在函数式编程中解释(正如Haskell和Scala中关于该主题的大量教程所证明的那样)。

Monads 是静态类型函数式语言的典型特征。要用OO语言描述它们,你可以想象一个界面。然后,实现的类将被称为“monadic”,前提是在实现实现时遵守所谓的“monad定律”。然后,该语言提供了一些语法糖,使使用类的实例变得有趣。MonadMonadMonadMonad

现在在Java中与monads无关,但是作为Java编译器特别处理的类型(Java 5附带的语法)的示例,请考虑以下几点:Iterableforeach

Iterable<Something> things = getThings(..);
for (Something s: things) {  /* do something with s */ }

因此,虽然我们可以在旧式循环中使用 的方法(和公司),但Java将这种语法糖作为特例授予我们。IterableIteratorhasNextfor

因此,就像实现并且必须遵守定律的类(例如:如果没有下一个元素就必须返回)在语法中有用一样 -会存在几个一元类,它们与相应的符号(在Haskell中称为)或Scala的符号一起有用。IterableIteratorIteratorhasNextfalseforeachdofor

所以——

  1. 什么是一元类的好例子?
  2. 处理它们的句法糖会是什么样子?

在Java 8中,我不知道 - 我知道lambda符号,但我不知道其他特殊的语法糖,所以我必须给你一个另一种语言的例子。

Monads通常用作容器类(列表就是一个例子)。Java已经有了这显然不是一元的,但这是Scala的:java.util.List

val nums = List(1, 2, 3, 4)
val strs = List("hello", "hola")
val result = for { // Iterate both lists, return a resulting list that contains 
                   // pairs of (Int, String) s.t the string size is same as the num.
  n <- nums        
  s <- strs if n == s.length 
} yield (n, s)
// result will be List((4, "hola")) 
// A list of exactly one element, the pair (4, "hola")

这是(大致)语法糖:

val nums = List(1, 2, 3, 4)
val strs = List("hello", "hola")
val results = 
nums.flatMap( n =>                 
  strs.filter(s => s.size == n).   // same as the 'if'
       map(s => (n, s))            // Same as the 'yield'
)
// flatMap takes a lambda as an argument, as do filter and map
// 

这显示了Scala的一个功能,其中monad被利用来提供列表推导

所以在 Scala 中 a 是一个 monad,因为它遵循 Scala 的 monad 定律,该定律规定所有 monad 实现都必须具有符合性和方法(如果你对这些定律感兴趣,“Monads 是大象”的博客条目是我迄今为止找到的最好的描述)。而且,正如你所看到的,lambdas(和HoF)是绝对必要的,但不足以使这种东西以实际的方式有用。ListflatMapmapfilter

除了容器式的monad之外,还有一堆有用的monad。他们有各种各样的应用。我最喜欢的一定是 Scala 中的 monad(Haskell 中的 monad),它是一种带来空安全的包装器类型:monad 的 Scala API 页面有一个非常简单的示例用法:http://www.scala-lang.org/api/current/scala/Option.html 在 Haskell 中,monads 在表示 IO 方面很有用,作为解决非一元 Haskell 代码具有不确定执行顺序这一事实的一种方式。OptionMaybeOption

拥有 lambdas 是进入函数式编程世界的第一小步;monads需要monad约定和足够大的可用monadic类型集,以及语法糖,以使与它们一起工作变得有趣和有用。

由于Scala可以说是最接近Java的语言,它也允许(一元)函数式编程,如果你(仍然)感兴趣,请查看Scala的Monad教程:http://james-iry.blogspot.jp/2007/09/monads-are-elephants-part-1.html

粗略的谷歌搜索显示,在Java中至少有一次尝试这样做:https://github.com/RichardWarburton/Monads-in-Java -

可悲的是,在Java中解释monads(即使使用lambdas)就像解释ANSI C(而不是C++或Java)中成熟的面向对象编程一样困难。


推荐