monads与Java 8

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

如果您从这里下载了预发布的兼容lambda的JDK8,则可以使用java来使用lambdaexpression式: 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); } 

只是供参考:

build议的JDK8可选类满足三个Monad法则 。 这是一个certificate这一点的要点 。

一个单子就是要提供符合三个规律的两个function。

这两个function:

  1. 值放入monadic上下文中

    • Haskell的Maybe: return / Just
    • 斯卡拉的select: Some
    • function性Java的选项: Option.some
    • JDK8的可选: Optional.of
  2. 在monadic上下文中应用一个函数

    • 哈斯克尔的可能: >>= (又名bind
    • Scala的选项: flatMap
    • Functional Java的选项: flatMap
    • JDK8的可选: flatMap

请参阅上述要点 ,以获得这三个法则的Java演示。

注意:要理解的关键之一是要应用于一元上下文函数的签名:它采用原始值types,并返回一元types。

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

 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)); 

你不需要任何forms的Monad接口来这样编码,或者这样想。 在斯卡拉,你不会编码到Monad接口(除非你正在使用Scalaz库…)。 看来,JDK8将使Java人们也能够使用这种链式一元计算方式。

希望这是有帮助的!

更新: 在这里博客。

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

Monad是静态types语言的一个典型特征。 用OO来描述它们,你可以想象一个Monad接口。 实现Monad类将被称为“monadic”,前提是在实现Monad ,实现服从所谓的“monad法则”。 然后语言提供了一些语法糖 ,使Monad类的实例有趣。

现在,Java中的Iterable与Monad没有任何关系,但是作为Java编译器特别对待的types(Java 5附带的foreach语法)的示例,请考虑以下事项:

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

因此,虽然我们可以使用IterableIterator方法( hasNext和company)进行旧式for循环,但Java将这种语法糖作为特殊情况授予我们。

所以就像实现IterableIterator必须遵守Iterator规则(例如:如果没有下一个元素, hasNext必须返回false )在foreach语法中是有用的一样 – 就会存在几个monadic类,这些monadic类对于相应的符号(就像在Haskell中调用)或Scala的符号一样。

所以 –

  1. 一元类的好例子是什么?
  2. 与它们打交道的语法糖是什么样的?

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

单子通常作为容器类(列表是一个例子)。 Java已经有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) st 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被利用来提供列表parsing。

所以Scala中的List是monad,因为它遵从Scala的monad法则,它规定所有的monad实现必须有符合flatMapmapfilter方法(如果你对法律感兴趣,“monads is elephants”博客条目有迄今为止我发现的最好的描述)。 而且,正如你所看到的,lambda(和HoF)是绝对必要的,不足以使这种事情以实用的方式有用。

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

lambdas是进入函数式编程世界的第一步, 单子需要monad惯例和足够大的一组可用的一元types, 以及语法糖,使他们有趣和有用的工作。

由于斯卡拉可以说是最接近Java的语言,也允许(单点)函数式编程,所以如果您仍然感兴趣,请查看Scala的Monad教程: http : //james-iry.blogspot.jp/2007/09/单子-都-大象-部分- 1.HTML

粗略的谷歌search表明,至less有一个尝试在Java中做到这一点: https : //github.com/RichardWarburton/Monads-in-Java –

不幸的是,在Java中解释monad(甚至是lambdaexpression式)和用ANSI C(而不是C ++或Java)解释全面的面向对象编程一样困难。

尽pipemonad可以用Java来实现,但是任何涉及它们的计算都注定会变成混淆的generics和花括号的混合。

我会说,Java绝对不是用来说明他们的工作或研究他们的意义和本质的语言。 为此,使用JavaScript或者支付一些额外的代价并学习Haskell会好得多。

无论如何,我正在向您表明我刚刚使用新的Java 8 lambdas实现了一个状态monad 。 这绝对是一个宠物项目,但它在一个不平凡的testing案例。

你可能会发现它在我的博客 ,但我会在这里给你一些细节。

状态monad基本上是一个状态到一对(状态,内容)的函数 。 你通常给这个状态一个genericstypesS和一个genericstypes的内容A.

因为Java没有对,我们必须使用特定的类对它们进行build模,我们称之为Scp(状态内容对),在这种情况下,它将具有genericstypesScp<S,A>和一个new Scp<S,A>(S state,A content)的构造函数new Scp<S,A>(S state,A content) 。 这样做后,我们可以说,monadic函数将有types

 java.util.function.Function<S,Scp<S,A>> 

这是@FunctionalInterface 。 也就是说,可以调用其唯一的实现方法,而不用命名它,传递一个正确types的lambdaexpression式。

StateMonad<S,A>主要是函数的一个包装。 它的构造函数可能会被调用,例如

 new StateMonad<Integer, String>(n -> new Scp<Integer, String>(n + 1, "value")); 

状态monad将该函数存储为一个实例variables。 然后有必要提供一个公共的方法来访问它,并将其提供给状态。 我决定把它s2scp (“state to state-content pair”)。

要完成monad的定义,你必须提供一个单元 (aka return )和一个绑定 (aka flatMap )方法。 我个人更喜欢将单位指定为静态,而绑定是实例成员。

在国家monad的情况下,单位得到如下:

 public static <S, A> StateMonad<S, A> unit(A a) { return new StateMonad<S, A>((S s) -> new Scp<S, A>(s, a)); } 

而绑定(作为实例成员)是:

 public <B> StateMonad<S, B> bind(final Function<A, StateMonad<S, B>> famb) { return new StateMonad<S, B>((S s) -> { Scp<S, A> currentPair = this.s2scp(s); return famb(currentPair.content).s2scp(currentPair.state); }); } 

你注意到绑定必须引入一个genericstypesB,因为它是允许链接异构状态monad的机制,并且赋予这个和其他monad显着的能力来将计算从一个types移动到另一个types。

我会在这里停止Java代码。 复杂的东西在GitHub项目中。 与以前的Java版本相比,lambda删除了大量的大括号,但是语法仍然非常复杂。

就像旁白一样,我正在展示如何用其他主stream语言编写类似的状态monad代码。 在Scala的情况下,绑定(在这种情况下必须被称为flatMap )读取像

 def flatMap[A, B](famb: A => State[S, B]) = new State[S, B]((s: S) => { val (ss: S, aa: A) = this.s2scp(s) famb(aa).s2scp(ss) }) 

而JavaScript中的绑定是我的最爱; 100%function,精益和平均,但当然无types:

 var bind = function(famb){ return state(function(s) { var a = this(s); return famb(a.value)(a.state); }); }; 

<无耻>我在这里砍了几个angular,但如果你对细节感兴趣,你可以在我的WP博客上find它们。</ shameless>

理解monad的唯一方法是编写一堆combinator库,注意到由此产生的重复,然后自己发现monad让你把这个重复分解出来。 在发现这一点的时候,每个人都build立了一个单子是什么的直觉…但是这个直觉并不是你可以直接与其他人交stream的东西 – 似乎每个人都必须经历同样的经验,组合器库的例子。 然而

在这里我find了一些学习Mondas的材料。

希望对你也有用。

codecommit

詹姆斯- iry.blogspot

debasishg.blogspot

这是关于单子的事情,很难把握:单子是一种模式,而不是一个特定的types。 Monads是一个形状,它们是一个抽象的接口(不是Java的意义),而不是一个具体的数据结构。 因此,任何示例驱动的教程都注定是不完整和失败的。 […]理解monads的唯一方法是看他们是什么:一个math结构。

Monads不是 Daniel Spiewak的隐喻


Monads在Java SE 8中

列表monad

 interface Person { List<Person> parents(); default List<Person> greatGrandParents1() { List<Person> list = new ArrayList<>(); for (Person p : parents()) { for (Person gp : p.parents()) { for (Person ggp : p.parents()) { list.add(ggp); } } } return list; } // <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) default List<Person> greatGrandParents2() { return Stream.of(parents()) .flatMap(p -> Stream.of(p.parents())) .flatMap(gp -> Stream.of(gp.parents())) .collect(toList()); } } 

也许monad

 interface Person { String firstName(); String middleName(); String lastName(); default String fullName1() { String fName = firstName(); if (fName != null) { String mName = middleName(); if (mName != null) { String lName = lastName(); if (lName != null) { return fName + " " + mName + " " + lName; } } } return null; } // <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) default Optional<String> fullName2() { return Optional.ofNullable(firstName()) .flatMap(fName -> Optional.ofNullable(middleName()) .flatMap(mName -> Optional.ofNullable(lastName()) .flatMap(lName -> Optional.of(fName + " " + mName + " " + lName)))); } } 

Monad是嵌套控制stream封装的通用模式。 即从嵌套的命令式成语中创build可重用的组件。

重要的是要明白monad不仅仅是一个包含平面映射操作的通用包装类。 例如,带有flatMap方法的ArrayList不会是monad。 因为monad法律禁止副作用。

Monad是一种forms主义 。 它描述的结构,无论内容或意义。 人们为了无意义的(抽象的)事而斗争。 所以他们拿出的不是单子的隐喻。

另见: Erik Meijer和Gilad Bracha之间的对话 。

这个博客文章提供了一个循序渐进的例子,说明如何在Java中实现Monadtypes(接口),然后用它来定义Maybe monad,作为一个实际应用。

这篇文章解释说,在Java语言中有一个monad,强调monad比许多程序员可能认为的更普遍,编码人员经常会不经意地重新创build它们 。

我喜欢用单纯的math(但仍然是非正式的)方式来思考monad。 之后,我将解释与Java 8的monad CompletableFuture之一的关系。

首先,monad M是一个函子 。 也就是说,它将一个types转换为另一个types:如果X是一个types(例如String ),那么我们有另一个typesM<X> (例如List<String> )。 而且,如果我们有一个types转换/函数X -> Y ,我们应该得到一个函数M<X> -> M<Y>

但是这样的单子有更多的数据。 我们有一个所谓的单位,它是每个typesX的函数X -> M<X> 。 换句话说, X每个对象都可以以自然的方式包装到monad中。

然而,monad的最具特色的数据是产品:对于每个typesX函数M<M<X>> -> M<X>

所有这些数据都应该满足一些公理,如函数性,结合性,单位法则等,但在此不赘述,实际使用也无关紧要。

我们现在可以推导出Monad的另一个操作,它常常用作monad的等价定义,绑定操作: M<X>值/对象可以绑定到函数X -> M<Y>以产生另一个值在M<Y> 。 我们如何做到这一点? 那么,首先我们对函数应用函子来获得函数M<X> -> M<M<Y>> 。 接下来,我们将一元产品应用于目标以获得函数M<X> -> M<Y> 。 现在我们可以根据需要插入M<X>的值来获得M<Y>的值。 这个绑定操作用于将多个monadic操作链接在一起。

现在让我们来看CompletableFuture的例子,即CompletableFuture = MCompletableFuture<MyData>的对象想象为一些asynchronous执行的计算,并在未来的某个时间产生一个MyData对象。 这里的一元操作是什么?

  • 函数是用方法来实现的thenApply :首先执行计算,一旦结果可用, thenApply的函数将结果转换成另一种types
  • monadic单元是用方法completedFuture实现的:正如文档所说,结果计算已经完成并且一次产生给定的值
  • 一元产品不是由一个函数实现的,但是下面的绑定操作等价于它(与函数一起),其语义含义如下:给定一个计算typesCompletableFuture<CompletableFuture<MyData>>计算asynchronous产生另一个在CompletableFuture<MyData>中进行计算,然后在MyData产生一些值,所以两个计算在另一个之后产生总计一个计算
  • 所产生的绑定操作是由方法thenCompose实现的

正如你所看到的,计算现在可以包含在一个特殊的上下文中,即asynchronous性 。 一般的一元结构使我们能够在给定的上下文中链接这样的计算。 例如,在Lagom框架中使用CompletableFuture可以轻松地构造高度asynchronous的请求处理程序,这些请求处理程序通过高效的线程池进行透明备份(而不是由专用线程处理每个请求)。