Même si les monades peuvent être mises en œuvre en Java, tout calcul impliquant eux est condamné à devenir un désordre mélange de médicaments génériques et des accolades.
Je dirais que Java est certainement pas la langue à utiliser pour illustrer leur travail ou à l'étude de leur sens et de l'essence. À cette fin, il est de loin préférable d'utiliser du Javascript ou de payer une partie de la différence de prix et d'apprendre Haskell.
De toute façon, je suis de signalisation vous que j'ai juste mis en place un état de monade à l'aide de la nouvelle Java 8 lambdas. C'est certainement un projet de compagnie, mais il fonctionne sur une base non négligeable de cas de test.
Vous pouvez trouver qu'il a présenté à http://wp.me/pY4ph-brmais je vais vous donner quelques détails ici.
Un état de monade est essentiellement une fonction à partir d'un état à un couple (état,le contenu). Vous avez l'habitude de donner à l'état un générique de type S et le contenu d'un type générique A.
Parce que Java n'a pas de paires que nous avons de les modéliser à l'aide d'une classe spécifique, appelons-la Scp (état-contenu paire), qui dans ce cas sera de type générique Scp<S,A>
et un constructeur new Scp<S,A>(S state,A content)
. Après cela, nous pouvons dire que la fonction monadique de type
java.util.function.Function<S,Scp<S,A>>
qui est un @FunctionalInterface
. C'est-à-dire que sa seule et unique méthode abstraite ne peut être invoquée sans la nommer, en passant d'une expression lambda avec le type de droit.
La classe StateMonad<S,A>
est principalement un wrapper autour de la fonction. Son constructeur ne peut être invoquée par ex. avec
new StateMonad<Integer, String>(n -> new Scp<Integer, String>(n + 1, "value"));
L'état de monade magasins de la fonction comme une variable d'instance. Il est alors nécessaire de fournir une méthode pour y accéder et de le nourrir à l'état. J'ai décidé de l'appeler s2scp
("l'état-contenu paire").
Pour terminer la définition de la monade, vous devez fournir une unité (aka retour) et bind (aka flatMap) de la méthode. Personnellement, je préfère préciser l'unité statique, alors que la liaison est un membre de l'instance.
Dans le cas de l'état de monade, l'unité doit être la suivante:
public static <S, A> StateMonad<S, A> unit(A a) {
return new StateMonad<S, A>((S s) -> new Scp<S, A>(s, a));
}
alors que bind (en tant que membre de l'instance) est:
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);
});
}
Vous remarquez que la liaison doit introduire un générique de type B, parce que c'est le mécanisme qui permet le chaînage de l'hétérogène, de l'état des monades et donne à cette et toutes les autres monade la capacité remarquable de déplacer le calcul de type de type.
J'avais arrêter ici avec le code Java. Le complexe des choses est dans le GitHub du projet. Par rapport aux précédentes versions de Java, les lambdas de supprimer un certain nombre d'accolades, mais la syntaxe est encore assez alambiquée.
Juste en aparté, je suis en montrant comment le même état monade code peut être écrit dans d'autres langages génériques. Dans le cas de la 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% fonctionnelle, maigre et moyenne, mais -bien sûr - sans type:
var bind = function(famb){
return state(function(s) {
var a = this(s);
return famb(a.value)(a.state);
});
};
<éhontée>
Je suis à la coupe un peu de coins ici, mais si vous êtes intéressé par les détails, vous les trouverez sur mon blog WP.</sans vergogne>