2014-05-17 23 views
6

Więc comonad.com ma interesującą serię artykułów na temat pracy z aplikacjami i staram się przynieść wszystko, co mogę, aby scala (dla zabawy i do nauki). Tak, Haskell definiuje FixF -Definiowanie Haskell FixF w scala

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

jest napisane”FixF jest od rodzaju ((* -> *) -> * -> *) -> * -> *) Zajmuje fixpoint o.«Drugiego rzędu funktora»(funktor, który wysyła funktora do innego funktora, czyli endofunctor na funkurze kategorii hask), aby odzyskać standardowy "Funktor pierwszego rzędu".

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

Teraz widziałem to

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

i ten

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

więc nie jest to pierwsza Fix (niewłaściwe rodzaje) Jest to drugie? Nie Think rodzaje rację

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

jest -

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

to jest?

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

jeśli tak bym chciała zobaczyć właściwą definicję i funktor

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] = ??? 

} 

teraz premia pytanie, może ktoś zdefiniowania aplikacyjnych?

+0

Czy należy to oznaczyć [python]? Nie rozumiem dlaczego? –

+0

@jb, nie ma powodu, aby oznaczyć to pytanie python. ponieważ oczywiście nie ma nic do pytona. – DEAD

Odpowiedz

8

To jest całkiem fajne pytanie. Przeczytałem również te posty i zastanawiałem się, jak przerażające będzie wyglądanie w Scali, ale nigdy tego nie wypróbowałem. Tak więc zamierzam odpowiedzieć w szczegółach, ale proszę zauważyć, że poniższe są wyjątkowo niegotowe (w końcu jest sobotni poranek) i niekoniecznie przedstawiają najczystszy sposób na zrobienie tego w Scali.

To chyba najlepiej zacząć od zdefiniowania niektórych typów z first post in the series:

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] 

i kilka więcej od 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]) 

Jeśli pracował przez wyżej, powinieneś poczuć, jak powinien wyglądać FixF:

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

Okazuje się, że jest to trochę zbyt surowe, choć, więc użyjemy następujące zamiast:

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

Załóżmy teraz chcemy wdrożyć list jako „fixpoint drugiego rzędu wielomianu funktorów” jak na blogu. Możemy zacząć od zdefiniowania kilka przydatnych aliasów:

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] 

A teraz możemy zdefiniować wersję Scala z przykładów ze stanowiska:

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

To wygląda to, czego oczekujemy, biorąc pod uwagę wdrożenie Haskell :

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

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

Teraz potrzebujemy naszych instancji klasy typów. Większość z nich jest całkiem prosta:

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

Włączając aplikacyjnej przykład dla FixF sobie:

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

Będziemy także zdefiniować transformację zacisk:

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

Ale teraz jesteśmy w tarapatach. Naprawdę potrzebujesz dodatkowej lenistwo tu, więc będziemy oszukiwać trochę:

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

Może istnieje sposób, aby uzyskać to do pracy z kodowaniem applicatives Scalaz 7 bez hack, ale jeśli nie ma I don” Chcę spędzić sobotnie popołudnie.

Tak, że jest do bani, ale przynajmniej teraz możemy sprawdzić naszą pracę:

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

który jest dokładnie to, co chcieliśmy.

+1

Awesome. bardzo doceniane. – DEAD

0

Tylko patrząc na typ danych Haskell, będę próbować następujące klasy:

import scala.language.higherKinds 

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

postaram się rozwinąć odpowiedź później, kiedy dowiedzieć się więcej o FixF.