Dav*_* L. 8 functional-programming scala function functor category-theory
在阅读此博客上的Functors说明时:
https://hseeberger.wordpress.com/2010/11/25/introduction-to-category-theory-in-scala/
Functor的一般定义和更具体的定义:
trait GenericFunctor[->>[_, _], ->>>[_, _], F[_]] {
def fmap[A, B](f: A ->> B): F[A] ->>> F[B]
}
trait Functor[F[_]] extends GenericFunctor[Function, Function, F] {
final def fmap[A, B](as: F[A])(f: A => B): F[B] =
fmap(f)(as)
}
Run Code Online (Sandbox Code Playgroud)
显然,这意味着Functors可以与除Function对象之外的其他更高级别的类型一起使用.有人可以举一个例子或解释如何或为什么或在什么情况下做?也就是说,GenericFunctor的另一个实现是什么?在Scala中 - 使用函数中的不同类型构造函数?谢谢!
编辑:
只是为了澄清:
object Functor {
def fmap[A, B, F[_]](as: F[A])(f: A => B)(implicit functor: Functor[F]): F[B] =
functor.fmap(as)(f)
implicit object ListFunctor extends Functor[List] {
def fmap[A, B](f: A => B): List[A] => List[B] =
as => as map f
}
}
scala> fmap(List(1, 2, 3))(x => x + 1)
res0: List[Int] = List(2, 3, 4)
Run Code Online (Sandbox Code Playgroud)
只是为了澄清,根据我的理解,ListFunctor在GenericFunctor中实现1-arg fmap,而repl transcript中的代码在Trait Functor中调用fmap,后者又调用fmap实现(例如在ListFunctor中).
这并没有改变整体问题,只是认为它会帮助人们尝试提供答案.任何见解将不胜感激.
在您的示例Functor中,Scala类型中的endofunctor带有Function1箭头.
还有其他类别.例如,想象一下对象是Scala类型的类别,A >~> B如果B是子类型,则有一个箭头A.Scalaz中的这个类别被称为Liskov.从Liskov类别到Function1类别有一个"健忘"的仿函数:
import scalaz._
import Scalaz._
trait Forget[F[-_]] extends GenericFunctor[>~>, Function1, F] {
def fmap[A, B](f: A >~> B): F[A] => F[B] = fa => f.subst(fa)
}
Run Code Online (Sandbox Code Playgroud)
请注意,您可以通过修复一个或多个参数来构建一些有趣的仿函数GenericFunctor.例如...
甲恒定算符在一个类别到另一个的单个对象的每个对象映射:
type ConstantFunctor[->>[_, _], ->>>[_, _], C] =
GenericFunctor[->>,->>>,({type F[x] = C})#F]
// def fmap[A, B](f: A ->> B): C ->>> C
Run Code Online (Sandbox Code Playgroud)
一个endofunctor类别映射到它自身:
type EndoFunctor[->>[_, _], F[_]] = GenericFunctor[->>, ->>, F]
// def fmap[A, B](f: A ->> B): F[A] ->> F[B]
Run Code Online (Sandbox Code Playgroud)
一个身份仿函数每一个物体和箭头映射到它自身:
type IdentityFunctor[->>[_, _]] = EndoFunctor[->>, ({type F[x] = x})#F]
// def fmap[A, B](f: A ->> B): A ->> B
Run Code Online (Sandbox Code Playgroud)
,当然,你的Functor特点仅仅是一个EndoFunctor在Function1类别.
type Functor[F[_]] = EndoFunctor[Function1, F]
// def fmap[A, B](f: A => B): F[A] => F[B]
Run Code Online (Sandbox Code Playgroud)
你可以想像它提升的实例的函子Either[A,B]到Either[F[A],F[B]]哪里F可以是一个List,Option等等.
编辑实现示例:
trait GenericFunctor[->>[_, _], ->>>[_, _], F[_]] {
def fmap[A, B](f: A ->> B): F[A] ->>> F[B]
}
trait EitherFunctor[F[_]] extends GenericFunctor[Either,Either,F]
object ListFunctor extends EitherFunctor[List] {
def fmap[A,B]( f: Either[A,B] ): Either[List[A],List[B]] =
f match {
case Left(a) => Left( List(a) )
case Right(b) => Right( List(b) )
}
}
Run Code Online (Sandbox Code Playgroud)
EDIT2另一个(也许是有用的)示例是带有从PartialFunction(类型->>)到Function(类型->>>)的仿函数:
trait PartialFunctor[F[_]]
extends GenericFunctor[PartialFunction,Function,F] {
final def fmap[A, B](as: F[A])(f: PartialFunction[A,B]): F[B] =
fmap(f)(as)
}
object OptionFunctor extends PartialFunctor[Option] {
def fmap[A,B]( f: PartialFunction[A,B] ): Option[A] => Option[B] =
(opt:Option[A]) => opt match {
case Some(a) => f.lift(a)
case None => None
}
}
object ListFunctor extends PartialFunctor[List] {
private def mapPartial[A,B]( f: PartialFunction[A,B], as: List[A] ): List[B] =
as match {
case Nil => Nil
case h :: t => if( f isDefinedAt h ) f(h) :: mapPartial( f, t )
else mapPartial( f, t )
}
def fmap[A,B]( f: PartialFunction[A,B] ): List[A] => List[B] =
(lst:List[A]) => mapPartial(f, lst)
}
Run Code Online (Sandbox Code Playgroud)
第二个示例允许实现collectScala集合中定义的操作:
def collect[A,B,F[_]]( as: F[A] )
( pf: PartialFunction[A,B] )
( implicit functor: PartialFunctor[F] ) =
functor.fmap( as )( pf )
Run Code Online (Sandbox Code Playgroud)