Free applicator in Scala

Looking through the free haskell package ( http://hackage.haskell.org/package/free-3.4.2 ), there are several types that seem simple and useful that I hardly see any literature on outside of haskell, the type that interests me now is applicative free. Now I believe that the free applicative method creates chains of functional applications as data and displays them (outside / above) G (I think ...)

where I am...

trait Functor[F[_]] { def map[A, B](f: A => B): F[A] => F[B] } trait Applicative[F[_]] extends Functor[F] { def ap[A, B](f: F[A => B]): F[A] => F[B] def apF[A, B](f: F[A])(x: F[A => B]): F[B] } trait FreeAp[F[_], A] { def map[B](f: A => B): FreeAp[F, B] = { this match { case Pure(x) => Pure(f(x)) case Ap(x, y) => Ap(x, { y.map(f.compose _) }) } } def runAp[G[_]](phi: F ~> G, fa: FreeAp[F, A])(implicit G: Applicative[G]): G[A] = { fa match { case Pure(x) => G.pure(x) case Ap(f, x) => G.apF(phi(f)) { G.map(id[A])(runAp(phi, x)) } } } def runApM[B, M](phi: F ~> ({ type l[x] = M })#l, x: FreeAp[F, B])(implicit M: Monoid[M]): M = { ??? } } case class Pure[F[_], A](x: A) extends FreeAp[F, A] case class Ap[F[_], A, B](x: F[A], y: FreeAp[F, A => B]) extends FreeAp[F, B] 

what I ask: runAp looks so simple in haskell, but I had problems with the translation ... I need to put it in the right direction

 runAp :: Applicative g => (forall x. fx -> gx) -> Ap fa -> ga runAp _ (Pure x) = pure x runAp u (Ap fx) = flip id <$> uf <*> runAp ux 

Ideally, I would like to gently go through the free application and help a little, at least with the execution of runAp (but I really delve into it and do not regret the details)

update: therefore, I myself worked with this, and I tried to implement the map, and I got a variance error, the second case expression gives an error if FreeAp is not contravariant in A, but the first case expression gives an error if FreeAp is not contravariant in A ... Any ideas?

update: I added the variance annotations from @Cirdec's answer and it didn’t work suddenly, but I played and added the [Any, B] annotation to the Ap construct on the map and now checks this type of definition. until lucky with runAp ...

update: this is a type error that I get on the Ap branches of the runAp pattern matching ...

 type mismatch; found : core01.FreeAp[F,Any => A] required: core01.FreeAp[F,A] 

////

 trait Forall[P[_]] { def apply[A]: P[A] } trait ~>[F[_], G[_]] { def apply[A](x: F[A]): G[A] } 

UPDATE reading: http://ro-che.info/articles/2013-03-31-flavours-of-free-applicative-functors.html , Free applicative functors Paolo Capriotti

 //// including the Functor & Applicative definitions above trait FreeAp[F[_], A] { self => def map[B](f: A => B): FreeAp[F, B] = { this match { case Pure(x) => Pure(f(x)) case ap: Ap[F, α, _] => Ap(ap.x.map(f.compose(_: α => A)), ap.y) } } } case class Pure[F[_], A](x: A) extends FreeAp[F, A] case class Ap[F[_], A, B](x: FreeAp[F, A => B], y: F[A]) extends FreeAp[F, B] def liftAp[F[_], A](x: F[A]): FreeAp[F, A] = Ap[F, A, A](Pure(id), x) def runAp[F[_], G[_], A](implicit G: Applicative[G]): (F ~> G) => FreeAp[F, A] => G[A] = { (u: F ~> G) => (fa: FreeAp[F, A]) => fa match { case Pure(x) => G.pure(x) case ap: Ap[F, α, _] => { val gf: G[(α => A) => A] = G.map(curry(flip(id[α => A])))(u(ap.y)) val gx: G[α => A] = runAp(G)(u)(ap.x) G.ap(gf)(gx) } } } trait FreeApFunctor[F[_]] extends Functor[({ type l[x] = FreeAp[F, x] })#l] { final override def map[A, B](f: A => B): FreeAp[F, A] => FreeAp[F, B] = _ map f } trait FreeApSemiapplicative[F[_]] extends Apply[({ type l[x] = FreeAp[F, x] })#l] with FreeApFunctor[F] { final def ap[A, B](f: => FreeAp[F, A => B]): FreeAp[F, A] => FreeAp[F, B] = { (fa: FreeAp[F, A]) => f match { case Pure(x) => map(x)(fa) case a: Ap[F, α, _] => Ap(ap{ map(flip[α, A, B])(ax) }(fa), ay) }// ^^^ // type mismatch; found : core01.FreeAp[F,α => _] required: core01.FreeAp[F,(α, A) => B] } } 
+7
scala haskell category-theory
source share
1 answer

Character traits

First, you need to get the correct Applicative and Functor values. Let's start with Functor . I am going to use Haskell names and arguments for everything where I can:

 class Functor f where fmap :: (a -> b) -> fa -> fb trait Functor[F[+_]] { def fmap[A,B]: (A => B) => F[A] => F[B] } 

Now Applicative . Your Applicative absent, and Applicative must be a Functor and that Applicative has a way to make it one of the values. The type for apF also seems wrong; it should allow you to apply a function stuck inside a functor to a value that is also stuck inside a functor.

 class Functor f => Applicative f where pure :: a-> fa (<*>) :: f (a -> b)-> fa -> fb trait Applicative[F[+_]] extends Functor[F] { def pure[A]: A => F[A] def apF[A,B]: F[A => B] => F[A] => F[B] } 

I would advise you to do something else that is applicative before jumping to a full application, perhaps the Identity functor and its applicative instance. Hope this helps you understand what you need to do for the free applicative instance.

Data Types and Deviations

Now we need data types.

 data Ap fa where Pure :: a -> Ap fa Ap :: fa -> Ap f (a -> b) -> Ap fb 

In Scala, they are represented by case classes:

 sealed abstract class FreeAp[F[+_],+A] case class Pure[F[+_], +A](a: A) extends FreeAp[F, A] case class Ap[F[+_], A, +B](x: F[A], fg: FreeAp[F,A=>B]) extends FreeAp[F, B] 

In order for the working Scala types to work, we annotated them with dispersion and correctly estimated the variance on our traits. This is normal in languages ​​with type variants; a similar interface in C # requires that the in and out annotations are generally useful and meet the expectations of programmers using libraries. If you really hate rejection, you can remove all change annotations from my answer, and it still works - you just won't have any interface options.

Instances

We can start porting instances for Functor and Applicative :

 instance Functor (Ap f) where fmap f (Pure a) = Pure (fa) fmap f (Ap xy) = Ap x ((f .) <$> y) instance Applicative (Ap f) where pure = Pure Pure f <*> y = fmap fy Ap xy <*> z = Ap x (flip <$> y <*> z) 

Functor and applicative instances

A functor instance in Scala is difficult to write because there are actually no universally quantified types. When using universally quantified flip and compose types, both can be used below without explicit types. We can get around this by binding a variable of type a , according to the pattern that is executed by the pattern ap: Ap[F,a,_] . A typical variable is used to provide explicit types .compose(_ : a => A) and flip[a,A,B] .

 class FreeApInstances[F[+_]] { implicit object FreeApApplicativeInstance extends Applicative[({type f[+x] = FreeAp[F, x]})#f] { // Functor final def fmap[A,B]: (A=>B) => FreeAp[F,A] => FreeAp[F,B] = (f: A=>B) => (fa: FreeAp[F,A]) => fa match { case Pure(a) => Pure(f(a)) case ap: Ap[F, a, _] => Ap(ap.x, fmap(f.compose(_ : a => A))(ap.fg)) } // Applicative final def pure[A]: A => FreeAp[F,A] = (a: A) => Pure(a) final def apF[A, B]: FreeAp[F,A=>B] => FreeAp[F,A] => FreeAp[F,B] = (ff: FreeAp[F,A=>B]) => (fa: FreeAp[F,A]) => ff match { case Pure(f) => fmap(f)(fa) case ap: Ap[F, a, _] => Ap(ap.x, apF(fmap(flip[a,A,B])(ap.fg))(fa)) } } } 

flip , which is required for Applicative , simply reverses the order of two arguments:

 def flip[A,B,C]: (A => B => C) => B => A => C = (f: (A => B => C)) => (b: B) => (a: A) => f(a)(b) 

runAp

Finally, we can runAp port:

 -- | Given a natural transformation from @ f@ to @ g@ , this gives a canonical monoidal natural transformation from @'Ap' f@ to @ g@. runAp :: Applicative g => (forall x. fx -> gx) -> Ap fa -> ga runAp _ (Pure x) = pure x runAp u (Ap fx) = flip id <$> uf <*> runAp ux 

This requires universal quantification for forall x. fx -> gx forall x. fx -> gx . We can satisfy this with the usual trick for languages ​​with generics - add a common element to something; the member can then provide something for all types, although we will need to explicitly specify the type. You have already explicitly found a Scala for natural transformations :

 trait ~>[F[_],G[_]] { def apply[B](f: F[B]): G[B] } 

Again, we bind a variable of type a from the ap: Ap[F, a _] template to get a type that Scala cannot infer, id: (a=>A) => a => A

 def runAp[F[_],G[_],A](implicit g: Applicative[G]): (F ~> G) => FreeAp[F,A] => G[A] = (u: F ~> G) => (fa: FreeAp[F,A]) => fa match { case Pure(x) => g.pure(x) case ap: Ap[F, a, _] => { val gf: G[(a=>A)=>A] = g.fmap(flip(id[a=>A]))(u.apply(ap.x)) val gx: G[a=>A] = runAp(g)(u)(ap.fg) g.apF(gf)(gx) } } 

id is only an identical function:

 def id[A]: A => A = (x:A) => x 
+8
source share

All Articles