Frage

Diese Frage ist nicht so schwer Köder gemeint! Wie es offensichtlich sein könnte, habe ich gesucht, unter Scalaz vor kurzem. Ich versuche zu verstehen, Warum ich einen Teil der Funktionalität benötigt, dass die Bibliothek zur Verfügung stellt. Hier ist etwas:

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

Ich habe ein paar println Aussagen in meinen Funktionen, um zu sehen, was los war ( beiseite: Was ich getan hätte, wenn ich vermeiden Nebenwirkungen wie das versuchte ?). Meine Funktionen sind:

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

Dann kombiniere ich sie über eine cokleisli und geben in einem NEL[Int]

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

Was bedeutet dieser Druck?

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

Der RES-Wert ist die Zeichenanzahl der (String) Elemente in der letzten NEL. Zwei Dinge fallen mir:

  1. Wie konnte ich gewusst, dass meine NEL auf diese Weise von den Methodensignaturen beteiligt reduziert werden würde? (Ich hatte nicht erwartet, das Ergebnis auf alle )
  2. Was ist der Sinn davon? Kann eine relativ einfache und leicht zu folgen für mich Anwendungsfall werden destilliert?

Diese Frage ist ein kaum verhüllte Plädoyer für einige schöne Person wie retronym erklären, wie diese leistungsstarke Bibliothek tatsächlich funktioniert.

War es hilfreich?

Lösung

Um das Ergebnis zu verstehen, müssen Sie die Comonad[NonEmptyList] Instanz verstehen. Comonad[W] sieht im Wesentlichen drei Funktionen (die eigentliche Schnittstelle in Scalaz ist ein wenig anders, aber das hilft bei der Erklärung):

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

So sieht Comonad eine Schnittstelle für einige Container W, die einen zu unterscheiden „Kopf“ Element (copure) und eine Möglichkeit, die innere Struktur des Behälters freigelegt, so dass wir pro Element einen Behälter erhalten (cojoin) mit einem jeweils gegebenes Element an der Spitze.

Die Art und Weise, dass dies für NonEmptyList implementiert ist, dass copure kehrt die Spitze der Liste, und cojoin gibt eine Liste von Listen, mit dieser Liste an der Spitze und alle Schwänzen dieser Liste am Heck.

Beispiel (ich bin NonEmptyList zu Nel verkürzt):

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

Die =>= Funktion ist coKleisli Zusammensetzung. Wie würden Sie zwei Funktionen f: W[A] => B und g: W[B] => C Komponieren, zu wissen nichts über sie anders als das W ist ein Comonad? Der Eingangstyp f und der Ausgangstyp g ist nicht kompatibel. Sie können jedoch map(f) zu bekommen und dann zusammensetzen, dass mit W[W[A]] => W[B] g. Jetzt, da ein W[A], können Sie es cojoin die W[W[A]] zu Futter in dieser Funktion zu erhalten. So ist die einzige vernünftige Zusammensetzung ist eine Funktion k, die die folgenden:

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

Also für Ihre nicht-leere Liste:

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

Andere Tipps

Cojoin wird auch definiert für scalaz .Tree und scalaz. TreeLoc . Dies kann sein ausgebeutet einen Strom aller Pfade von der Wurzel des Baumes zu jedem Blattknoten zu finden.

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

Mit coKleisli Zusammensetzung Pfeil, wir können dies tun, zum Beispiel:

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

leafDist nimmt einen Baum und gibt eine Kopie davon mit jedem Knoten mit seinem maximalen Abstand von einem Blatt mit Anmerkungen versehen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top