8

在阅读函子的描述在此博客:Scala - 如何在非函数类型上使用函子?

https://hseeberger.wordpress.com/2010/11/25/introduction-to-category-theory-in-scala/

有函子的一个通用的定义,更具体的一个:

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

显然,这意味着函子可以与其它用于除函数对象外还有更高级的类型。有人可以举一个例子或解释如何或为什么或在什么情况下会做?也就是说,GenericFunctor的另一个实现是在Scala中使用了一个与Function不同的类型构造函数?谢谢!

编辑:

只是为了澄清:

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) 

只是为了澄清,根据我的理解ListFunctor实现了GenericFunctor 1-ARG FMAP而在REPL成绩单代码调用特质的FMAP Functor,然后调用fmap实现(例如在ListFunctor中)。

这并没有改变整体问题,只是认为它会帮助人们试图提供答案。任何见解提供将不胜感激。

回答

7

在您的例子Functor是Scala类型与Function1类别为箭头的endofunctor。

还有其他的分类。例如,设想一个类别,其中对象是Scala类型,如果BA的子类型,则有一个箭头A >~> BScalaz中的这个类别被称为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) 
} 

注意,您可以通过固定的一个或多个参数来GenericFunctor建立一些有趣的函子。例如...

恒定算符在一个类别中的每个对象映射到单个对象在另一:

type ConstantFunctor[->>[_, _], ->>>[_, _], C] = 
    GenericFunctor[->>,->>>,({type F[x] = C})#F] 
// def fmap[A, B](f: A ->> B): C ->>> C 

一种endofunctor的类别映射到它自身:

type EndoFunctor[->>[_, _], F[_]] = GenericFunctor[->>, ->>, F] 
// def fmap[A, B](f: A ->> B): F[A] ->> F[B] 

身份仿函数将每个对象和箭头映射到自身:

type IdentityFunctor[->>[_, _]] = EndoFunctor[->>, ({type F[x] = x})#F] 
// def fmap[A, B](f: A ->> B): A ->> B 

,当然还有,你Functor特点是刚刚在Function1类别的EndoFunctor

type Functor[F[_]] = EndoFunctor[Function1, F] 
// def fmap[A, B](f: A => B): F[A] => F[B] 
6

你能想象一个算符其中升降机的Either[A,B]一个实例为其中Either[F[A],F[B]]F可以是ListOption

EDIT实现例如:

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

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) 

} 

这第二个实施例允许实现collect操作在Scala集合定义:

def collect[A,B,F[_]](as: F[A]) 
        (pf: PartialFunction[A,B]) 
        (implicit functor: PartialFunctor[F]) = 
    functor.fmap(as)(pf) 
+0

我不认为这两个函子是一个仿函数。我看不出你将如何实施任一类别。 – Anonymous

相关问题