2014-05-17 8 views
6

So comonad.com hat eine interessante Reihe von Artikeln über die Arbeit mit Applicatives und ich habe versucht zu bringen, was ich kann zu scala (zum Spaß und zu lernen). Also, Haskell definiert FixF -Definieren von Haskell FixF in Scala

newtype FixF f a = FixF (f (FixF f) a) 

geschrieben steht:“FixF ist von Art ((* -> *) -> * -> *) -> * -> *) Es nimmt die Fixpoint eines. "Zweiter Ordnung Functor"(ein Functor, die eine Functor an einen anderen Functor sendet, das heißt ein endofunctor in der Funktor-Kategorie von hask), um einen Standard "Functor erster Ordnung" wieder herzustellen. "

kinds classify types 
*     type A 
* -> *    type F[_] 
* -> * -> *   type F[_,_] 
((* -> *) -> *)  type F[F'[_]] 
((* -> *) ->* -> *) type F[F'[_], A] 

Jetzt habe ich diese

case class Fix[F[_]](out: F[Fix[F]]) 
// ((* -> *) -> *) 

und diesen

case class BFixF[F[_,_], A](out: F[A, BFixF[F,A]]) 

es ist nicht die erste Fix (falsche Arten) Ist es die zweite So gesehen? Ich glaube nicht, das die Arten richtig sind

BFixF :: ((* -> * -> *) -> * -> *) ? 

ist es -

// edit as of this morning it is really not this 
    class FixF[F[_[_], _], A] :: ((* -> *) -> * -> *) -> *) 

ist es?

case class FixF'[F[_], A](run: F[Fix[F, A]]) 

wenn ja würde ich gerne die richtige Definition sehen und Funktors

case class FixF[F[_], A] (out: F[Fix[F, A]]) 

trait FixFFunctor[F[_]: Functor] extends Functor[({type l[x] = FixF[F, x]})#l] { 

    def map[A, B](f: A => B): FixF[F, A] => FixF[F, B] = ??? 

} 

jetzt Frage Bonus, kann jemand die applicative definieren?

+0

Sollte dies markiert werden [Python]? Ich verstehe nicht warum? –

+0

@jb, gibt es überhaupt keinen Grund, diese Frage Python zu markieren. wie es offensichtlich nichts zu python hat. – DEAD

Antwort

8

Das ist eine ziemlich coole Frage - ich habe diese Beiträge auch gelesen und mich gefragt, wie schrecklich eine Scala-Implementierung aussehen würde, aber ich habe es nie wirklich versucht. Also werde ich etwas genauer darauf eingehen, aber bitte beachten Sie, dass das Folgende extrem unkonventionell ist (es ist immerhin Samstagmorgen) und nicht unbedingt der sauberste Weg, dies in Scala zu tun.

Es ist wahrscheinlich am besten durch die Definition nur einige der Arten von den first post in the series zu starten:

import scala.language.higherKinds 
import scalaz._, Scalaz._ 

case class Const[M, A](mo: M) 

sealed trait Sum[F[_], G[_], A] 

object Sum { 
    def inL[F[_], G[_], A](l: F[A]): Sum[F, G, A] = InL(l) 
    def inR[F[_], G[_], A](r: G[A]): Sum[F, G, A] = InR(r) 
} 

case class InL[F[_], G[_], A](l: F[A]) extends Sum[F, G, A] 
case class InR[F[_], G[_], A](r: G[A]) extends Sum[F, G, A] 

Und ein paar mehr von den blog post itself:

case class Embed[F[_], A](out: A) 

case class ProductF[F[_[_], _], G[_[_], _], B[_], A](f: F[B, A], g: G[B, A]) 

Wenn Sie noch durch die oben gearbeitet, Sie sollten ein Gefühl dafür haben, wie FixF aussehen sollte:

case class FixF[F[f[_], _], A](out: F[({ type L[x] = FixF[F, x] })#L, A]) 

Es stellt sich heraus, dass dies ein wenig zu streng ist, obwohl, so dass wir die folgenden statt:

class FixF[F[f[_], _], A](v: => F[({ type L[x] = FixF[F, x] })#L, A]) { 
    lazy val out = v 
    override def toString = s"FixF($out)" 
} 

Nehmen wir nun an wollen wir implementieren Listen als „zweiter Ordnung Fixpoint von Polynom functors“, wie im Blogbeitrag. Wir können durch die Definition einige nützliche Aliase starten:

type UnitConst[x] = Const[Unit, x] 
type UnitConstOr[F[_], x] = Sum[UnitConst, F, x] 
type EmbedXUnitConstOr[F[_], x] = ProductF[Embed, UnitConstOr, F, x] 

type MyList[x] = FixF[EmbedXUnitConstOr, x] 

Und jetzt können wir die Scala Version der Beispiele aus dem Amt definieren:

val foo: MyList[String] = new FixF[EmbedXUnitConstOr, String](
    ProductF[Embed, UnitConstOr, MyList, String](
    Embed("foo"), 
    Sum.inL[UnitConst, MyList, String](Const()) 
) 
) 

val baz: MyList[String] = new FixF[EmbedXUnitConstOr, String](
    ProductF[Embed, UnitConstOr, MyList, String](
    Embed("baz"), 
    Sum.inL[UnitConst, MyList, String](Const()) 
) 
) 

val bar: MyList[String] = new FixF[EmbedXUnitConstOr, String](
    ProductF[Embed, UnitConstOr, MyList, String](
    Embed("bar"), 
    Sum.inR[UnitConst, MyList, String](baz) 
) 
) 

Das sieht aus wie, was wir die Haskell Umsetzung gegeben erwarten würde :

scala> println(foo) 
FixF(ProductF(Embed(foo),InL(Const(())))) 

scala> println(bar) 
FixF(ProductF(Embed(bar),InR(FixF(ProductF(Embed(baz),InL(Const(()))))))) 

Jetzt brauchen wir unsere Art Klasseninstanzen. Die meisten davon sind ziemlich einfach:

implicit def applicativeConst[M: Monoid]: Applicative[ 
    ({ type L[x] = Const[M, x] })#L 
] = new Applicative[({ type L[x] = Const[M, x] })#L] { 
    def point[A](a: => A): Const[M, A] = Const(mzero[M]) 
    def ap[A, B](fa: => Const[M, A])(f: => Const[M, A => B]): Const[M, B] = 
    Const(f.mo |+| fa.mo) 
} 

implicit def applicativeEmbed[F[_]]: Applicative[ 
    ({ type L[x] = Embed[F, x] })#L 
] = new Applicative[({ type L[x] = Embed[F, x] })#L] { 
    def point[A](a: => A): Embed[F, A] = Embed(a) 
    def ap[A, B](fa: => Embed[F, A])(f: => Embed[F, A => B]): Embed[F, B] = 
    Embed(f.out(fa.out)) 
} 

implicit def applicativeProductF[F[_[_], _], G[_[_], _], B[_]](implicit 
    fba: Applicative[({ type L[x] = F[B, x] })#L], 
    gba: Applicative[({ type L[x] = G[B, x] })#L] 
): Applicative[({ type L[x] = ProductF[F, G, B, x] })#L] = 
    new Applicative[({ type L[x] = ProductF[F, G, B, x] })#L] { 
    def point[A](a: => A): ProductF[F, G, B, A] = 
     ProductF(fba.point(a), gba.point(a)) 
    def ap[A, C](fa: => ProductF[F, G, B, A])(
     f: => ProductF[F, G, B, A => C] 
    ): ProductF[F, G, B, C] = ProductF(fba.ap(fa.f)(f.f), gba.ap(fa.g)(f.g)) 
    } 

Einschließlich der applicative Instanz für FixF selbst:

implicit def applicativeFixF[F[_[_], _]](implicit 
    ffa: Applicative[({ type L[x] = F[({ type M[y] = FixF[F, y] })#M, x] })#L] 
): Applicative[({ type L[x] = FixF[F, x] })#L] = 
    new Applicative[({ type L[x] = FixF[F, x] })#L] { 
    def point[A](a: => A): FixF[F, A] = new FixF(ffa.pure(a)) 
    def ap[A, B](fa: => FixF[F, A])(f: => FixF[F, A => B]): FixF[F, B] = 
     new FixF(ffa.ap(fa.out)(f.out)) 
    } 

Wir werden auch das Terminal Transformation definieren:

implicit def terminal[F[_], M: Monoid]: F ~> ({ type L[x] = Const[M, x] })#L = 
    new (F ~> ({ type L[x] = Const[M, x] })#L) { 
    def apply[A](fa: F[A]): Const[M, A] = Const(mzero[M]) 
    } 

Aber jetzt wir sind in Schwierigkeiten. Wir müssen wirklich etwas mehr Faulheit hier, so dass wir ein wenig betrug:

def applicativeSum[F[_], G[_]](
    fa: Applicative[F], 
    ga: => Applicative[G], 
    nt: G ~> F 
): Applicative[({ type L[x] = Sum[F, G, x] })#L] = 
    new Applicative[({ type L[x] = Sum[F, G, x] })#L] { 
    def point[A](a: => A): Sum[F, G, A] = InR(ga.point(a)) 
    def ap[A, B](x: => Sum[F, G, A])(f: => Sum[F, G, A => B]): Sum[F, G, B] = 
     (x, f) match { 
     case (InL(v), InL(f)) => InL(fa.ap(v)(f)) 
     case (InR(v), InR(f)) => InR(ga.ap(v)(f)) 
     case (InR(v), InL(f)) => InL(fa.ap(nt(v))(f)) 
     case (InL(v), InR(f)) => InL(fa.ap(v)(nt(f))) 
     } 
    } 

implicit def myListApplicative: Applicative[MyList] = 
    applicativeFixF[EmbedXUnitConstOr](
    applicativeProductF[Embed, UnitConstOr, MyList](
     applicativeEmbed[MyList], 
     applicativeSum[UnitConst, MyList](
     applicativeConst[Unit], 
     myListApplicative, 
     terminal[MyList, Unit] 
    ) 
    ) 
) 

Vielleicht gibt es eine Möglichkeit, dies mit Scalaz 7s Codierung von applicatives ohne Hack zur Arbeit zu kommen, aber wenn es mir don‘ Ich möchte meinen Samstagnachmittag damit verbringen, es herauszufinden.

Damit saugt, aber zumindest jetzt können wir unsere Arbeit überprüfen:

scala> println((foo |@| bar)(_ ++ _)) 
FixF(ProductF(Embed(foobar),InL(Const(())))) 

das ist genau das, was wir wollten.

+1

Ehrfürchtig. sehr geschätzt. – DEAD

0

Gerade indem Sie den Datentyp Haskell suchen, würde ich die folgende Klasse versuchen:

import scala.language.higherKinds 

class FixF[F[_,_],A](val ffix: F[FixF[F,_],A]) extends AnyVal; 

Ich werde versuchen, die Antwort später zu erweitern, wenn ich mehr über FixF lernen.

Verwandte Themen