Monades avec Java 8

Dans le but d’aider à comprendre ce qu’est une monade, quelqu’un peut-il donner un exemple en utilisant Java? Sont-ils possibles?

Les expressions lambda sont possibles en utilisant Java si vous téléchargez le JDK8 compatible pré-version lambda à partir d’ici http://jdk8.java.net/lambda/

Un exemple de lambda utilisant ce JDK est présenté ci-dessous. Quelqu’un peut-il fournir une monade relativement simple?

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

Juste FYI:

La classe facultative JDK8 proposée satisfait aux trois lois Monad . Voici un résumé qui démontre cela.

Il suffit à un Monad de fournir deux fonctions conformes à trois lois.

Les deux fonctions:

  1. Placer une valeur dans un contexte monadique

    • Haskell est peut-être: return / Just
    • Option de Scala: Some
    • Option Java fonctionnelle: Option.some
    • JDK8’s Facultatif: Optional.of
  2. Appliquer une fonction dans un contexte monadique

    • Haskell est peut-être: >>= (aka bind )
    • Option de Scala: flatMap
    • Option Java fonctionnelle: flatMap
    • JDK8’s Facultatif: flatMap

S’il vous plaît voir la liste ci – dessus pour une démonstration java des trois lois.

NOTE: Une des choses clés à comprendre est la signature de la fonction à appliquer dans un contexte monadique : elle prend le type de valeur brut et renvoie le type monadique.

En d’autres termes, si vous avez une instance de Optional , les fonctions que vous pouvez passer à sa méthode flatMap auront la signature (Integer) -> Optional , où U est un type de valeur qui ne doit pas nécessairement être Integer , par exemple Ssortingng :

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

Vous n’avez besoin d’aucune interface Monad pour coder de cette façon ou pour réfléchir de cette manière. Dans Scala, vous ne codez pas vers une interface Monad (sauf si vous utilisez la bibliothèque Scalaz …). Il semble que JDK8 permettra également aux utilisateurs de Java d’utiliser ce style de calcul monadique enchaîné .

J’espère que c’est utile!

Mise à jour: Blogué à ce sujet ici .

Java 8 aura lambdas; les monades sont une toute autre histoire. Ils sont assez difficiles à expliquer dans la functional programming (comme en témoigne le grand nombre de tutoriels sur le sujet dans Haskell et Scala).

Les monades sont une caractéristique typique des langages fonctionnels typés statiquement. Pour les décrire en langage OO, vous pouvez imaginer une interface Monad . Les classes qui implémentent Monad seraient alors appelées «monadiques», à condition que, dans la mise en œuvre de Monad la mise en œuvre obéisse à ce que l’on appelle les «lois monades». Le langage fournit alors du sucre syntaxique qui rend le travail avec des instances de la classe Monad intéressant.

Maintenant, ce que l’on peut Iterable en Java n’a rien à voir avec les monades, mais comme exemple d’un type que le compilateur Java traite spécialement (la syntaxe foreach fournie avec Java 5), ​​considérez ceci:

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

Alors que nous aurions pu utiliser les méthodes hasNext ( hasNext et company) dans une ancienne boucle for Java, Java nous accorde ce sucre syntaxique comme cas particulier .

Donc, de même que les classes implémentant Iterable et Iterator doivent respecter les lois de l’ Iterator (Exemple: hasNext doit retourner false s’il n’y a pas d’élément suivant) pour être utile dans la syntaxe foreach – il existe plusieurs classes monadiques utiles (comme on l’appelle en Haskell) ou Scala for notation.

Alors –

  1. Quels sont les bons exemples de classes monadiques?
  2. À quoi ressemblerait le sucre syntaxique pour les traiter?

Dans Java 8, je ne sais pas – je connais la notation lambda mais je ne connais pas d’autres types de sucre syntaxique, alors je vais devoir vous donner un exemple dans une autre langue.

Les monades servent souvent de classes de conteneurs (les listes sont un exemple). Java a déjà java.util.List qui n’est évidemment pas monadique, mais voici 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, Ssortingng) st the ssortingng 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") 

Ce qui est (grossièrement) du sucre syntaxique pour:

 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 // 

Cela montre une fonctionnalité de Scala où les monades sont exploitées pour fournir des listes compréhensibles .

Donc, une List dans Scala est une monade, car elle obéit aux lois de la monade de Scala, qui stipulent que toutes les implémentations flatMap doivent être conformes à des flatMap , map et filter (si les lois vous intéressent, meilleure description que j'ai trouvée jusqu'à présent. Et, comme vous pouvez le voir, les lambdas (et HoF) sont absolument nécessaires mais pas suffisants pour rendre ce genre de chose utile d’une manière pratique.

Il y a un tas de monades utiles en plus des monstres-conteneurs. Ils ont toutes sortes d'applications. Mon favori doit être la monade Option dans Scala (la monade Maybe dans Haskell), qui est un type d'encapsulation qui apporte une sécurité nulle : la page de l'API Scala pour le monade Option a un exemple très simple d'utilisation: http: //www.scala -lang.org/api/current/scala/Option.html Dans Haskell, les monades sont utiles pour représenter IO, comme moyen de contourner le fait que le code Haskell non monadique a un ordre d'exécution indéterminé.

Avoir des lambdas est un premier pas dans le monde de la functional programming; Les monades requièrent à la fois la convention de monade et un ensemble suffisamment large de types monadiques utilisables, ainsi que du sucre syntaxique pour rendre leur utilisation amusante et utile.

Puisque Scala est sans doute le langage le plus proche de Java qui permet également la functional programming (monadique), regardez ce tutoriel Monad pour Scala si vous êtes (encore) intéressé: http://james-iry.blogspot.jp/2007/09/ monads-are-elephants-part-1.html

Un jogging superficiel montre qu'il y a au moins une tentative de le faire en Java: https://github.com/RichardWarburton/Monads-in-Java -

Malheureusement, expliquer les monades en Java (même avec lambdas) est aussi difficile que d’expliquer une programmation orientée object en C ANSI (au lieu de C ++ ou Java).

Même si les monades peuvent être implémentées en Java, tout calcul les impliquant est condamné à devenir un mélange désordonné de génériques et d’accolades.

Je dirais que Java n’est certainement pas le langage à utiliser pour illustrer leur travail ou pour étudier leur signification et leur essence. Pour cela, il est préférable d’utiliser JavaScript ou de payer un supplément et d’apprendre le Haskell.

Quoi qu’il en soit, je vous signale que je viens de mettre en place une monade d’état utilisant les nouveaux lambdas Java 8 . C’est certainement un projet de compagnie, mais cela fonctionne sur un cas de test non sortingvial.

Vous pouvez le trouver présenté sur mon blog , mais je vais vous donner quelques détails ici.

Une monade d’état est essentiellement une fonction allant d’un état à une paire (état, contenu) . Vous donnez généralement à l’état un type générique S et le contenu un type générique A.

Comme Java n’a pas de paires, nous devons les modéliser en utilisant une classe spécifique, appelons-la Scp (paire état-contenu), qui dans ce cas aura un type générique Scp et un constructeur new Scp(S state,A content) . Après avoir fait cela, nous pouvons dire que la fonction monadique aura le type

 java.util.function.Function> 

qui est une @FunctionalInterface . Cela signifie que sa seule et unique méthode d’implémentation peut être appelée sans la nommer, en passant une expression lambda avec le bon type.

La classe StateMonad est principalement une enveloppe autour de la fonction. Son constructeur peut être appelé par exemple avec

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

La monade d’état stocke la fonction en tant que variable d’instance. Il est alors nécessaire de fournir une méthode publique pour y accéder et lui fournir l’état. J’ai décidé de l’appeler s2scp (“paire d’état à contenu d’état”).

Pour compléter la définition de la monade, vous devez fournir une méthode unitaire (aka return ) et une méthode bind (aka flatMap ). Personnellement, je préfère spécifier unit comme statique, alors que bind est un membre d’instance.

Dans le cas de la monade d’état, l’unité doit être la suivante:

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

while bind (en tant que membre d’instance) est:

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

Vous remarquez que bind doit introduire un type générique B, car c’est le mécanisme qui permet l’enchaînement de monades d’états hétérogènes et donne à cette monade et à toute autre une remarquable capacité à déplacer le calcul de type en type.

Je m’arrêterais ici avec le code Java. Les choses complexes sont dans le projet GitHub. Par rapport aux versions précédentes de Java, lambdas supprime beaucoup d’accolades, mais la syntaxe est encore assez compliquée.

En passant, je montre comment un code d’état similaire peut être écrit dans d’autres langues grand public. Dans le cas de Scala, bind (qui dans ce cas doit être appelé flatMap ) se lit comme

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

alors que la liaison en JavaScript est mon préféré; 100% fonctionnel, maigre et méchant mais bien sûr:

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

Je coupe quelques coins ici, mais si vous êtes intéressé par les détails, vous les trouverez sur mon blog WP.

Le seul moyen de comprendre les monades consiste à écrire un ensemble de bibliothèques de combinateurs, à noter la duplication qui en résulte, puis à découvrir par vous-même que les monades vous permettent de prendre en compte cette duplication. En découvrant cela, tout le monde construit une intuition pour ce qu’est une monade… mais cette intuition n’est pas le genre de chose que vous pouvez communiquer directement à quelqu’un – il semble que tout le monde doit vivre la même expérience exemples de bibliothèques de combinateurs. toutefois

Ici, j’ai trouvé du matériel pour apprendre le Mondas.

J’espère vous être utile aussi.

codecommit

james-iry.blogspot

debasishg.blogspot

Voici la chose à propos des monades qui est difficile à comprendre: les monades sont un modèle, pas un type spécifique. Les monades sont une forme, elles sont une interface abstraite (pas dans le sens de Java) plus qu’elles ne sont une structure de données concrète. En conséquence, tout tutoriel basé sur des exemples est voué à l’incomplétude et à l’échec. […] La seule façon de comprendre les monades est de les voir pour ce qu’elles sont: une construction mathématique.

Les monades ne sont pas des métaphores par Daniel Spiewak


Monades en Java SE 8

Liste monade

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

Peut-être monade

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

Monad est un modèle générique pour l’encapsulation de stream de contrôle nestede . C’est un moyen de créer des composants réutilisables à partir des idiomes impératifs nesteds.

Important de comprendre qu’une monade n’est pas simplement une classe de wrapper générique avec une opération de carte plate . Par exemple, ArrayList avec une méthode flatMap ne sera pas une monade. Parce que les lois monades interdisent les effets secondaires.

Monad est un formalisme . Il décrit la structure, indépendamment du contenu ou de la signification. Les gens ont du mal à se rapporter à des choses (abstraites) dénuées de sens. Donc, ils inventent des métaphores qui ne sont pas des monades.

Voir aussi: conversation entre Erik Meijer et Gilad Bracha.

Cet article de blog donne un exemple détaillé de la manière dont vous pourriez implémenter un type Monad (interface) en Java, puis l’utiliser pour définir le monad Maybe, en tant qu’application pratique.

Cet article explique qu’il existe une monade dans le langage Java, soulignant le fait que les monades sont plus courantes que ce que de nombreux programmeurs peuvent penser et que les codeurs les réinventent souvent par inadvertance .

J’aime penser aux monades de façon légèrement plus mathématique (mais toujours informelle). Après cela, j’expliquerai la relation avec l’une des monades CompletableFuture de Java 8.

Tout d’abord, une monade M est un foncteur . Autrement dit, il transforme un type en un autre type: Si X est un type (par exemple, Ssortingng ), nous avons un autre type M (par exemple, List ). De plus, si on a une transformation / fonction X -> Y de types, on devrait avoir une fonction M -> M .

Mais il y a plus de données pour une telle monade. Nous avons une unité appelée fonction X -> M pour chaque type X En d’autres termes, chaque object de X peut être enveloppé de manière naturelle dans la monade.

Les données les plus caractéristiques d’une monade sont toutefois son produit: une fonction M> -> M pour chaque type X

Toutes ces données devraient satisfaire certains axiomes tels que la fonctorialité, l’associativité, les lois d’unité, mais je n’entrerai pas dans les détails ici et cela n’a pas d’importance pour l’utilisation pratique.

Nous pouvons maintenant en déduire une autre opération pour les monades, souvent utilisée comme définition équivalente pour les monades, l’opération de liaison: une valeur / un object dans M peut être lié avec une fonction X -> M pour donner une autre valeur dans M . Comment pouvons-nous y parvenir? Eh bien, nous appliquons d’abord la fonctorialité à la fonction pour obtenir une fonction M -> M> . Ensuite, nous appliquons le produit monadique à la cible pour obtenir une fonction M -> M . Maintenant, nous pouvons twigr la valeur de M pour obtenir une valeur en M comme souhaité. Cette opération de liaison est utilisée pour enchaîner plusieurs opérations monadiques.

Maintenant, venons à l’exemple CompletableFuture , à savoir CompletableFuture = M Pensez à un object de CompletableFuture comme à un calcul effectué de manière asynchrone et qui MyData un object MyData dans le futur. Quelles sont les opérations monadiques ici?

  • la fonction est réalisée avec la méthode thenApply : le calcul est d’abord effectué et dès que le résultat est disponible, la fonction donnée à thenApply est appliquée pour transformer le résultat en un autre type
  • l’unité monadique est réalisée avec la méthode completedFuture : comme l’indique la documentation, le calcul résultant est déjà terminé et donne la valeur donnée en une fois
  • le produit monadique n’est pas réalisé par une fonction, mais l’opération de liaison ci-dessous lui est équivalente (avec la fonctorialité) et sa signification sémantique est simplement la suivante: étant donné un calcul de type CompletableFuture> le calcul dans CompletableFuture qui, à son tour, MyData une valeur dans MyData suite, si bien que l’exécution des deux calculs après l’autre donne un calcul total
  • l’opération de liaison résultante est réalisée par la méthode thenCompose

Comme vous le voyez, les calculs peuvent maintenant être regroupés dans un contexte particulier, à savoir l’ asynchronicité . Les structures monadiques générales nous permettent de chaîner ces calculs dans un contexte donné. CompletableFuture est par exemple utilisé dans le framework Lagom pour construire facilement des gestionnaires de requêtes hautement asynchrones sauvegardés de manière transparente par des pools de threads efficaces (au lieu de traiter chaque requête par un thread dédié).