So I've been trying to push my intuitions of functors to their limits by defining a higher order functor i.e. a, F that takes 1st order types as type argument, and functions and lifts functions on 1st order types to this higher context in scala something like
trait Functor1[F[_[_]] {
def hmap[X[_], Y[_]] : (X ~> Y) => F[X] => F[Y]
}
I've been trying to define some of the map derivable functions of the normal functor e.g.
trait Functor[F[_]] {
def map[A, B] : (A => B) => F[A] => F[B]
// there's a few more besides this that are map derivable
def distribute[A,B](fab: F[(A, B)]): (F[A], F[B])
}
but I can't write anything that type checks... I'm just playing but I wonder if anyone else has been down this road that's smarter than me
can a higher order functor be defined in scala ? if not then in haskell ?
Not sure what are your goals, but this typechecks
import scala.language.higherKinds
trait Functor1[F[G[_]]]{
def hmap[X[_], Y[_]]:(X ~> Y) => F[X] => F[Y]
}
case class FId[Z,F[_]](f:F[Z])
implicit def Functor1Id[Z] = new Functor1[({type L[G[_]]=FId[Z,G]})#L]{
def hmap[X[_], Y[_]]:(X ~> Y) => FId[Z,X] => FId[Z,Y]= ???
}
(I added the Z parameter because I wanted to avoid existentials and I had to use the "type lambda" trick)
Do you want to define a map for a "functor of a functor"? I think I did something similar (here called composition):
case class Comp[F[_],G[_],Z](unComp:F[G[Z]])
implicit def fcomp[F[_], G[_]](implicit ff:Functor[F], fg:Functor[G])=new Functor[({ type abs[A]=Comp[F,G,A]})#abs]{
def fmap[A,B](fga:Comp[F,G,A])(f: A => B):Comp[F,G,B]= Comp(ff.fmap(fga.unComp)(fg.fmap(_)(f)))
}
I've been toying with functors in scala-reggen but I don't think I'm the smart one, as I mainly did it by fumbling around (and checking Scalaz for inspiration)
/** Higher order functor */
trait HFunctor[F[_]] {
def ffmap[G[_]: Functor, A, B](f: A => B): F[G[A]] => F[G[B]]
def hfmap[G[_], H[_]](t: G ~> H): ({type λ[α] = F[G[α]]})#λ ~> ({type λ[α] = F[H[α]]})#λ
}
trait Functor[F[_]] { self =>
def fmap[A, B](f: A => B): F[A] => F[B]
// derived
def map[A, B](x: F[A])(f: A => B): F[B] = fmap(f)(x)
def strengthL[A, B]: A => F[B] => F[(A, B)] = a => f => fmap((x: B) => (a, x))(f)
def strengthR[A, B]: F[A] => B => F[(A, B)] = f => b => fmap((x: A) => (x, b))(f)
def compose[G[_]](implicit e: Functor[G]): Functor[({ type λ[α] = F[G[α]]})#λ] =
new Functor[({ type λ[α] = F[G[α]]})#λ] {
def F = self;
def G = e
def fmap[A, B](f: A => B) = F.fmap(G.fmap(f))
}
}
object Functor {
@inline def apply[F[_]: Functor]: Functor[F] = iev
}
trait Coyoneda[F[_], A] { co =>
type I
def fi: F[I]
def k: I => A
final def run(implicit F: Functor[F]): F[A] = F.fmap(k)(fi)
final def map[B](f: A => B): Coyoneda.Aux[F, B, I] =
Coyoneda(fi)(f compose k)
final def trans[G[_]](phi: F ~> G): Coyoneda[G, A] =
Coyoneda(phi(fi))(k)
}
object Coyoneda {
type Aux[F[_], A, B] = Coyoneda[F, A] { type I = B }
def apply[F[_], B, A](x: F[B])(f: B => A): Aux[F, A, B] =
new Coyoneda[F, A] {
type I = B
val fi = x
val k = f
}
implicit def coyonedaFunctor[F[_]]: Functor[({ type λ[α] = Coyoneda[F, α] })#λ] =
new Functor[({ type λ[α] = Coyoneda[F, α] })#λ] {
def fmap[A, B](f: A => B): Coyoneda[F, A] => Coyoneda[F, B] =
x => apply(x.fi)(f compose x.k)
}
implicit def coyonedaHFunctor: HFunctor[({ type λ[F[_]] = ({ type λ[α] = Coyoneda[F, α] })#λ })#λ] =
new HFunctor[({ type λ[F[_]] = ({ type λ[α] = Coyoneda[F, α] })#λ })#λ] {
def ffmap[G[_]: Functor, A, B](f: A => B): Coyoneda[G, A] => Coyoneda[G, B] = _.map(f)
def hfmap[F[_], G[_]](t: F ~> G): (({ type λ[α] = Coyoneda[F, α] })#λ ~> ({ type λ[α] = Coyoneda[G, α] })#λ) =
new (({ type λ[α] = Coyoneda[F, α] })#λ ~> ({ type λ[α] = Coyoneda[G, α] })#λ) {
def apply[A](x: Coyoneda[F, A]) = x.trans(t)
}
}
def liftCoyoneda[F[_], A](fa: F[A]): Coyoneda[F, A] = apply(fa)(x => x)
def lowerCoyoneda[F[_]: Functor, A](c: Coyoneda[F, A]): F[A] = c.run
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With