Question

Cette question ne vise pas comme appât de la flamme! Comme il peut être évident, je l'ai regardé Scalaz récemment. Je suis en train de comprendre pourquoi J'ai besoin certaines des fonctionnalités que la bibliothèque offre. Voici quelque chose:

import scalaz._
import Scalaz._
type NEL[A] = NonEmptyList[A]
val NEL = NonEmptyList

Je mets quelques instructions println dans mes fonctions pour voir ce qui se passait ( de côté: qu'aurais-je fait si je tentais d'éviter les effets secondaires comme ça ). Mes fonctions sont:

val f: NEL[Int] => String    = (l: NEL[Int]) => {println("f: " + l); l.toString |+| "X" }
val g: NEL[String] => BigInt = (l: NEL[String]) => {println("g: " + l);  BigInt(l.map(_.length).sum) }

Alors je les combine par un cokleisli et passer dans un NEL[Int]

val k = cokleisli(f) =>= cokleisli(g)
println("RES: "  + k( NEL(1, 2, 3) ))

Qu'est-ce que cette impression?

f: NonEmptyList(1, 2, 3)
f: NonEmptyList(2, 3)
f: NonEmptyList(3)
g: NonEmptyList(NonEmptyList(1, 2, 3)X, NonEmptyList(2, 3)X, NonEmptyList(3)X)
RES: 57

La valeur RES est le nombre de caractères des éléments (String) dans le NEL final. Deux choses me viennent à:

  1. Comment aurais-je su que mon NEL allait réduire de cette manière des signatures de méthode impliqués? (Je ne m'y attendais pas le résultat tout )
  2. Quel est le point de tout cela? Peut raisonnablement simple et cas facile à suivre l'utilisation distiller pour moi?

Cette question est un plaidoyer à peine voilée pour une personne belle comme retronym pour expliquer comment cette puissante bibliothèque fonctionne réellement.

Était-ce utile?

La solution

Pour comprendre le résultat, vous devez comprendre l'instance Comonad[NonEmptyList]. Comonad[W] fournit essentiellement trois fonctions (l'interface réelle Scalaz est un peu différent, mais cela aide à expliquer):

map:    (A => B) => W[A] => W[B]
copure: W[A] => A
cojoin: W[A] => W[W[A]]

Ainsi, Comonad fournit une interface pour un certain W conteneur qui comporte un élément « tête » unique (de copure) et un moyen d'exposition de la structure intérieure du récipient de telle sorte que nous obtenons un conteneur par élément (cojoin), chacun avec un élément donné à la tête.

La façon dont cela est mis en œuvre pour NonEmptyList est que copure retourne la tête de la liste, et cojoin renvoie une liste de listes, cette liste à la tête et les queues de cette liste à la queue.

Exemple (je raccourcissant NonEmptyList à Nel):

Nel(1,2,3).copure = 1
Nel(1,2,3).cojoin = Nel(Nel(1,2,3),Nel(2,3),Nel(3))

La fonction =>= est coKleisli composition. Comment voulez-vous composer deux fonctions f: W[A] => B et g: W[B] => C, ne sachant rien à leur sujet autre que celui W est un Comonad? Le type d'entrée de f et le type de sortie de g ne sont pas compatibles. Cependant, vous pouvez map(f) pour obtenir W[W[A]] => W[B] puis composez qu'avec g. Maintenant, étant donné un W[A], vous pouvez cojoin pour obtenir le W[W[A]] pour alimenter cette fonction. Ainsi, la seule composition raisonnable est une k de fonction qui effectue les opérations suivantes:

k(x) = g(x.cojoin.map(f))

Donc, pour votre liste non vide:

g(Nel(1,2,3).cojoin.map(f))
= g(Nel(Nel(1,2,3),Nel(2,3),Nel(3)).map(f))
= g(Nel("Nel(1,2,3)X","Nel(2,3)X","Nel(3)X"))
= BigInt(Nel("Nel(1,2,3)X","Nel(2,3)X","Nel(3)X").map(_.length).sum)
= BigInt(Nel(11,9,7).sum)
= 27

Autres conseils

Cojoin est également défini pour scalaz .Tree et scalaz. TreeLoc . Cela peut être exploitée pour trouver un cours d'eau de tous les chemins de la racine de l'arbre à chaque nœud feuille.

def leafPaths[T](tree: Tree[T]): Stream[Stream[T]]
  = tree.loc.cojoin.toTree.flatten.filter(_.isLeaf).map(_.path)

Utilisation de la composition coKleisli de flèche, nous pouvons le faire, par exemple:

def leafDist[A] = (cokleisli(leafPaths[A]) &&& cokleisli(_.rootLabel))
  =>= (_.map(s => (s._2, s._1.map(_.length).max)))

leafDist prend un arbre et retourne une copie de celui-ci à chaque noeud annoté avec sa distance maximale d'une feuille.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top