与Java的单子8(Monads with Java 8)

2019-07-03 23:11发布

在帮助了解一个单子是什么利益,可以使用Java有人提供了一个例子吗? 他们是可能的吗?

Lambda表达式是可能的,如果你从这里下载预发布拉姆达兼容JDK8用java http://jdk8.java.net/lambda/

使用该JDK的λ的一个例子如下所示,可有人提供一个相对简单单子?

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

Answer 1:

仅供参考:

所提出的JDK8可选类确实满足三个单子法律 。 这里有一个要点证明这一点。

它所需要的是一个单子是提供一种符合三个定律两种功能。

这两个函数:

  1. 将一个值一元上下文

    • Haskell的可能: return / Just
    • Scala的选项: Some
    • Java功能的选项: Option.some
    • JDK8的可选: Optional.of
  2. 适用于一元上下文中功能

    • Haskell的可能: >>= (又名bind
    • Scala的选项: flatMap
    • Java功能的选项: flatMap
    • JDK8的可选: flatMap

请参阅上述要点为三个定律一个java演示。

注:其中一个关键的事情要明白的是在一元范围内应用功能的签名:它需要的原始值类型,并返回一元型。

换句话说,如果有的实例Optional<Integer> ,则各功能可以通到其flatMap方法将有签名(Integer) -> Optional<U>其中U是不必须是一个值类型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));

你不需要任何形式的单子接口,以这种方式代码,或者有这样的想法。 在Scala中,你不代码到一个单子接口(除非您使用Scalaz库...)。 看来,JDK8将授权Java的人使用链式一元计算的这种风格也是如此。

希望这是有帮助的!

更新:博客上讲述这个在这里 。



Answer 2:

Java的8将有lambda表达式; 单子是一个完全不同的故事。 他们是够硬的函数式编程来解释(如由在Haskell和斯卡拉主题的大量教程)。

单子静态类型函数式语言的典型特征。 来形容他们在面向对象的说话,你能想象一个Monad接口。 实现类Monad将被称为“单子”,前提是在实施Monad实施遵循所谓的“单子法律”。 语言则提供了与所述的情况下工作的一些语法糖 Monad类有趣。

现在Iterable的Java有无关单子,但作为一个类型的Java编译器将特殊(的的例子foreach与Java 5的语法来了),考虑一下:

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

因此,虽然我们可以使用IterableIterator方法( hasNext在旧式和公司) for循环,Java的赐予我们这个语法糖作为一种特殊情况

因此,正如实现类IterableIterator必须遵守Iterator法(例如: hasNext必须返回false ,如果没有下一个元素)是有用foreach语法-也就存在一些单子类,这将是有用的相应do记号(因为它在Haskell称)或Scala的for符号。

所以 -

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

在Java 8,我不知道 - 我知道拉姆达符号的,但我不知道其他特殊语法糖,所以我得给你另一种语言的例子。

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

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的特征。

因此,一个List中Scala是一个单子,因为它遵循Scala的单子法律,其中规定所有单子的实现必须符合flatMapmapfilter方法(如果你有兴趣在法律中,“单子大象”博客条目有到目前为止,我已经找到了最好的说明)。 而且,正如你可以看到,lambda表达式(和HOF)是绝对必要的 ,但还不足以使这种事情在实际的方式是有用的。

有一群除了容器十岁上下的人有用的单子也是如此。 他们有各种各样的应用。 我最喜欢的一定是Option在斯卡拉(单子Maybe在Haskell单子),这是导致空安全的包装类型:对于Scala的API页面Option单子有一个非常简单的使用例子: HTTP://www.scala -lang.org/api/current/scala/Option.html在Haskell,单子是在表示IO有用的,因为周围的非一元Haskell代码具有执行的不确定的顺序的事实的一种工作方式。

有lambda表达式是第一小步成函数式编程的世界; 单子需要两个单子惯例和足够大的一套可用的单子类型, 以及语法糖,使与他们一起工作的乐趣和有用的。

由于Scala是可以说是最接近的语言对Java也允许(一元)函数式编程,你看这个单子教程Scala的,如果你是(仍然)兴趣: http://james-iry.blogspot.jp/2007/09/单子-都-大象-部分- 1.HTML

粗略谷歌上搜索显示,有至少一个企图在Java中做到这一点: https://github.com/RichardWarburton/Monads-in-Java -

不幸的是,在Java解释单子(即使lambda表达式)是硬如说明ANSI C盛放的面向对象程序设计(而不是C ++或Java)。



Answer 3:

即使单子可以用Java来实现,涉及到他们的任何计算是注定要成为仿制药和大括号的杂乱组合。

我会说,Java是绝对不会为了使用说明他们的工作或研究它们的含义和本质的语言。 为了这个目的,那最好是使用JavaScript或付出一些额外的代价和学习哈斯克尔。

无论如何,我发出信号通知您,我使用新的Java 8 Lambda表达式只是实现了一个状态单子 。 这绝对是一个宠物项目,但它工作在一个不平凡的测试用例。

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

甲状态单子基本上是从一个状态到一对(状态,内容)的功能 。 您通常给国家通用型S和内容泛型类型A.

因为Java没有我们使用一个特定的类对他们的模型对,我们称之为SCP(国有含量对),在这种情况下将有通用型Scp<S,A>和构造new Scp<S,A>(S state,A content) 。 这样做之后,我们可以说,一元函数有型

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

这是一个@FunctionalInterface 。 这就是说,它的唯一的实现方法可以在不命名它,传递一个lambda表达式使用正确的类型调用。

StateMonad<S,A>主要是围绕功能的包装。 它的构造函数可以调用例如用

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

状态单子存储功能作为一个实例变量。 然后有必要提供一个公共方法来访问它和饲料它的状态。 我决定把它s2scp (“国家与国家,内容对”)。

为了完成你必须提供一个单位 (又名返回 )的单子和绑定 (又名flatMap)方法的定义。 我个人偏好来指定单元为静态的,而绑定是一个实例成员。

在状态单子的情况下,单元得是以下:

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

您会注意到绑定必须引入泛型类型B,因为它是允许异类状态单子的链接,并给出了这一点,任何其他单子卓越能力,计算从类型移到输入机制。

我想在这里停止与Java代码。 复杂的东西是在GitHub的项目。 相比于以前的Java版本,lambda表达式删除了很多花括号,但语法仍然是相当令人费解。

正如顺便说一句,我展示了如何相似的单子状态代码可能等主流语言编写。 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%的功能,精简的意思是,但-of课程 - 无类型:

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

<无耻>我在这里而省几个小钱,但如果你有兴趣的细节,你会发现他们对我的WP博客。</无耻>



Answer 4:

了解单子的唯一途径是通过写一串组合子库,注意所产生的重复,然后发现自己是单子让你分析出这种重复。 在发现这个,每个人都建立了一些直觉的单子是什么...但这种直觉是不是那种东西,你可以给别人直接沟通 - 似乎每个人都必须经过从一些具体的推广,以单子相同的经历组合子库的例子。 然而

在这里,我发现了一些材料学Mondas。

希望能对您有用了。

codecommit

詹姆斯- iry.blogspot

debasishg.blogspot



Answer 5:

下面是关于单子的事情是很难把握:单子都是一个模式,而不是特定类型。 单子的形状,它们是一个抽象的接口(未在Java意义上)超过它们的具体数据结构。 其结果是,任何例如驱动教程注定不完备性和故障。 [...]了解单子的唯一方法就是看看他们,他们是什么:一个数学结构。

单子不是隐喻由Daniel Spiewak


在Java SE 8单子

单子列出

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

也许单子

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

单子是用于嵌套控制流封装的通用图案。 即一种方式来创建嵌套的命令的习惯用法可重用的组件。

重要的是要明白,一个单子不只是一个普通的包装类与平面地图操作。 例如, ArrayListflatMap方法将不会是一个单子。 因为单子法律禁止的副作用。

单子是一种形式主义 。 据介绍,无论内容或意义的结构。 人与无意义的(抽象)的事情作斗争。 于是,他们想出了隐喻哪些不是单子。

另请参见: 谈话埃里克·梅杰和吉拉德·布拉彻之间。



Answer 6:

本博客文章给出了一个如何在Java中实现一个单子类型(接口),然后用它来定义也许单子,作为一个实际应用一步一步的例子。

这篇文章解释说,是建立在Java语言中的一个单子,强调单子比许多程序员可能会想和程序员往往更常见的点在不经意间重塑他们 。



Answer 7:

我喜欢在slighlty更数学(但仍是非正式的)方式去思考单子。 在那之后,我将解释为Java 8的单子CompletableFuture的一个关系。

首先,一个单子M仿函数 。 即,变换一种类型为另一种类型:如果X是一种类型的(例如String ),那么我们有另一种类型的M<X>例如List<String> )。 此外,如果我们有一个转换/功能的X -> Y的类型,我们应该得到一个函数M<X> -> M<Y>

但是,还有更多的数据,以这样的单子。 我们有一个所谓的单元,其是一个函数X -> M<X>对于每种类型的X 。 换言之,每个对象X可以被包裹在一种自然的方式进入单子。

一个单子的最具特征性的数据,但是,是它的产品:一个函数M<M<X>> -> M<X>对于每种类型的X

所有这些数据都应该满足一些公理一样functoriality,关联性,单位的法律,但我不会细讲这里,它也无所谓了实际应用。

现在,我们可以推导出单子另一操作,其通常用作用于单子的等效定义,装订操作:在一个值/对象M<X>可以与函数的约束X -> M<Y>以产生另一个值在M<Y> 。 我们如何实现这一目标? 嗯,首先我们运用functoriality的函数来获取函数M<X> -> M<M<Y>> 。 接下来,我们将一元产品到目标以获得函数M<X> -> M<Y> 现在,我们可以在的值插头M<X>获得的值M<Y>如所期望。 这种结合操作用于链几个单子操作在一起。

现在让我们来到CompletableFuture例子,即CompletableFuture = M 。 想的对象的CompletableFuture<MyData>做为所异步地执行和产生的一个目的一些计算MyData作为结果在未来的一段时间。 什么是这里的一元操作?

  • functoriality实现该方法thenApply :首先进行计算,一旦该结果是可用的,这是考虑到功能thenApply被施加到结果转换成另一种类型的
  • 所述一元单元实现与所述方法completedFuture :作为文档讲述,将得到的计算已经完成,并产生所述给定值在一次
  • 不是由函数实现一元产物,但低于所述结合操作等效于它(与functoriality一起)和它的语义是简单地执行以下操作:给定类型的计算CompletableFuture<CompletableFuture<MyData>>该计算异步地产生另一个在计算CompletableFuture<MyData>这又产生在一些值MyData以后,所以在总在其它产率后一个计算既进行计算
  • 将所得的结合操作是由该方法实现thenCompose

正如你看到的,计算现在可以在一个特殊的背景,即异步包裹起来。 一般的一元结构,使我们能够链在给定的情况下这样的计算。 CompletableFuture是例如在Lagom框架用于容易地构建其通过有效的线程池透明地备份高度异步请求处理程序(而不是处置由专用线程每个请求)。



Answer 8:

尽管所有的争论Optional满意,还是不行,单子法律,我平时喜欢看StreamOptionalCompletableFuture以同样的方式。 事实上,所有的人提供了一个flatMap()这是所有我关心,让我拥抱(由埃里克·梅耶尔引用)的“ 副作用雅致组成 ”。 因此,我们可以有相应的StreamOptionalCompletableFuture以下列方式:

关于单子,我通常会简化,只思考flatMap()从课程由Erik梅耶尔“ 反应式编程的原则 ”):



文章来源: Monads with Java 8