Scala - 如何在非函数类型上使用函子? [英] Scala -- How to use Functors on non-Function types?

查看:107
本文介绍了Scala - 如何在非函数类型上使用函子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读本博客Funators的描述时:

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]
}
特征Functor [F [_]]扩展了GenericFunctor [函数,函数,F] {
final def fmap [A​​,B](as:F [A] )(f:A => B):F [B] =
fmap(f)(as)
}

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



编辑:

只需澄清:

  object Functor {

def fmap [A​​,B,F [_]](as:F [A])(f:A => B)隐式函数:Functor [F]):F [B] =
functor.fmap(as)(f)

隐式对象ListFunctor extends Functor [List] {
def fmap [A​​,B](f:A => B):List [A] =>列表[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 transcript中的代码在Trait Functor中调用fmap,它然后调用fmap实现(例如在ListFunctor中)。



这并没有改变整体问题,只是认为它会帮助人们试图提供答案。在您的示例中, Functor 是一个类型为Scala类型的endofunctor,其中 Function1 为箭头。

还有其他类别。例如,设想一个对象是Scala类型的类别,并且有一个箭头 A>〜> B 如果 B A 的子类型。 Scalaz 中的这一类别称为 Liskov 。从 Liskov 类别到 Function1 类别有一个健忘仿函数:

  import scalaz._ 
import Scalaz._
trait忘记[F [-_]]扩展了GenericFunctor [>〜> ;,函数1,F] {
def fmap [A​​,B](f:A>〜> B):F [A] => F [B] = fa => f.subst(fa)
}

请注意,您可以通过修复一些有趣的函数一个或多个 GenericFunctor 的参数。例如...
$ b

一个常量函子将一个类别中的每个对象映射到另一个类别中的单个对象:

 类型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 [ - >>,({类型F [x] = x})#F] 
// def fmap [A​​,B](f:A->> B):A - >> B

当然,您的 Functor 特质只是 EndoFunctor Function1 类别中。



<$ p $ f $ A $ B $ {code> type Functor [F [_]] = EndoFunctor [Function1,F]
// def fmap [A​​,B](f:A => B):F [A ] => F [B]


While reading the description of Functors on this blog:

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

there is a generic definition of Functor and a more specific one:

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

Clearly this means Functors can be used with other higher-kinded types besides Function objects. Could someone please give an example or explain how or why or in what scenario that would be done? Namely, what would another implementation of GenericFunctor be in Scala -- that uses a different type constructor from Function? Thanks!

EDIT:

Just to clarify:

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)

Just to clarify, according to my understanding ListFunctor implements the 1-arg fmap in GenericFunctor while the code in the repl transcript calls the fmap in Trait Functor, which in turn calls an fmap implementation (e.g. in ListFunctor).

This doesn't change the overall question, just thought it would help people trying to provide answers. Any insights provided would be appreciated.

解决方案

In your example Functor is an endofunctor in the category of Scala types with Function1 as arrows.

There are other categories. For example, imagine a category in which the objects are Scala types, and there is an arrow A >~> B if B is a subtype of A. This category in Scalaz is called Liskov. There is a "forgetful" functor from the Liskov category to the Function1 category:

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

Note that you can build some interesting functors by fixing one or more of the arguments to GenericFunctor. For example...

A constant functor maps every object in one category to a single object in another:

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

An endofunctor maps a category to itself:

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

An identity functor maps every object and arrow to itself:

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

And of course, your Functor trait is just an EndoFunctor in the Function1 category.

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

这篇关于Scala - 如何在非函数类型上使用函子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆