/ / Higher order Functors in scala - scala, haskell, category-theory

Wyższe porządki Funktorzy w scala - scala, haskell, teoria kategorii

Więc próbowałem przeforsować moje intuicjefunktorów do ich granic definiując funktor wyższego rzędu, np. a, F, który przyjmuje typy pierwszego rzędu jako argument typu, i funkcje i podnosi funkcje w typach pierwszego rzędu do tego wyższego kontekstu w scala coś jak

trait Functor1[F[_[_]] {
def hmap[X[_], Y[_]] : (X ~> Y) => F[X] => F[Y]
}

Próbowałem zdefiniować niektóre funkcje, które można uzyskać z funkcji normalnego funktora, np.

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

ale nie mogę napisać niczego, co sprawdza typ ... Po prostu gram, ale zastanawiam się, czy ktokolwiek inny był na tej drodze, który jest mądrzejszy ode mnie

Czy w scala można zdefiniować funktor wyższego rzędu? jeśli nie to w haskell?

Odpowiedzi:

2 dla odpowiedzi № 1

Nie jestem pewien, jakie są twoje cele, ale ten 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]= ???
}

(Dodałem parametr Z, ponieważ chciałem uniknąć egzystencji i musiałem użyć sztuczki "typu lambda")

Czy chcesz zdefiniować mapę dla "funktora funktora"? Myślę, że zrobiłem coś podobnego (tutaj nazwanego kompozycją):

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

Bawiłem się z funktorami w scala-reggen ale nie uważam, że jestem mądry, ponieważ robiłem to przede wszystkim, grzebiąc w pobliżu (i sprawdzając Scalaz dla inspiracji)


1 dla odpowiedzi nr 2
/** 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

}