所以我一直试图通过定义一个更高阶的函子来将我的函子的直觉推到极限,即a,将一阶类型作为类型参数的F,以及函数和提升第一阶类型的函数到此scala中更高的上下文,如
trait Functor1[F[_[_]] {
def hmap[X[_], Y[_]] : (X ~> Y) => F[X] => F[Y]
}
我一直试图定义普通仿函数的一些地图可导函数,例如。
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])
}
但是我不能写任何类型检查的东西...... 我只是在玩,但我想知道是否还有其他人在这条路上比我更聪明
可以在scala中定义更高阶的仿函数吗?如果不是那么在哈斯克尔?
答案 0 :(得分:3)
不确定你的目标是什么,但这个类型检查
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]= ???
}
(我添加了Z参数因为我想避免存在而我必须使用"输入lambda"技巧)
你想为一个仿函数"的仿真器定义一个地图吗? 我想我做了类似的事情(这里称为组合):
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)))
}
我在scala-reggen玩弄了仿函数,但我不认为我是聪明的玩家,因为我主要是通过摸索(并检查Scalaz的灵感)来做到这一点。
答案 1 :(得分:1)
/** 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
}