Pregunta

Esta pregunta no se entiende como la llama cebo! Como podría ser evidente, he estado buscando en Scalaz recientemente. Estoy tratando de entender ¿Por qué Necesito algunas de las funcionalidades que ofrece la biblioteca. de aquí algo:

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

Me puso algunas sentencias println en mis funciones para ver lo que estaba pasando ( a un lado: ¿qué habría hecho si yo estaba tratando de efectos secundarios que evitar como ?). Mis funciones son:

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

A continuación, las combino a través de un cokleisli y paso en un NEL[Int]

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

Lo que hace esta impresión?

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

El valor RES es el recuento de caracteres de los elementos (String) en el NEL final. Hay dos cosas que se me ocurren:

  1. ¿Cómo podría haber sabido que mi NEL se va a reducirse de este modo de las firmas de los métodos involucrados? (Yo no estaba esperando el resultado en absoluto )
  2. ¿Cuál es el punto de esto? ¿Puede un simple y razonablemente caso de uso fácil de seguimiento destilar para mí?

Esta pregunta se hace un llamamiento velado escasamente por alguna persona encantadora como retronym para explicar cómo esta poderosa biblioteca realmente funciona.

¿Fue útil?

Solución

Para entender el resultado, es necesario entender la instancia Comonad[NonEmptyList]. Comonad[W] proporciona esencialmente tres funciones (la interfaz real en Scalaz es un poco diferente, pero esto ayuda con la explicación):

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

Así, Comonad proporciona una interfaz para algunos W contenedor que tiene un elemento distinguido "cabeza" (copure) y una forma de exponer la estructura interna del recipiente de modo que obtenemos un contenedor por elemento (cojoin), cada uno con una elemento dado en la cabeza.

La forma en que esto se implementa para NonEmptyList es que copure vuelve la cabeza de la lista, y cojoin devuelve una lista de listas, con esta lista en la cabeza y todas las colas de esta lista en la cola.

Ejemplo (estoy acortando NonEmptyList a Nel):

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

La función =>= es la composición coKleisli. ¿Cómo compones dos funciones f: W[A] => B y g: W[B] => C, sin saber nada acerca de ellos aparte de eso es un W Comonad? El tipo de entrada de f y el tipo de salida de g no son compatibles. Sin embargo, se puede conseguir map(f) W[W[A]] => W[B] y luego que la componen con g. Ahora, dado un W[A], puede cojoin para obtener el W[W[A]] de alimentación en esa función. Por lo tanto, la composición única razonable es un k función que hace lo siguiente:

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

Así que para su lista no vacía:

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

Otros consejos

Cojoin también se define para scalaz .Tree y scalaz. Treeloc . Esto puede ser href="http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleTree.scala.html#13383" explotada encontrar una corriente de todos los caminos de la raíz del árbol a cada nodo hoja.

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

El uso de coKleisli flecha composición, podemos hacer esto, por ejemplo:

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

leafDist toma un árbol y devuelve una copia de la misma con cada nodo anotado con su distancia máxima de una hoja.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top