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

相關問題