Functor 有什么用?
How are Functors useful?
我们知道任何泛型类型 F[_]
withmap
方法,符合某些 laws,是一个 函子 。例如,List[_]
、Option[_]
和 F[A] = Env => A
是函子。我只是想知道这个函子抽象是否有意义。
我如何利用它们是仿函数这一事实?您能否展示一个使用 map
并且实际有用的非平凡计算示例?
好吧,一旦你知道某个东西是 Functor,你不仅会得到 map
,你还会得到所有你可以用它派生的函数
例如,可以以适用于任何仿函数的方式派生函数 lift
。
Lift 将 "lift" 函数从 A => B
到 F[A] => F[B]
对于某些 Functor F[_]
并定义为
def lift[A, B](f: A => B): F[A] => F[B] = map(_)(f)
如果您使用的库 cats or scalaz then you get these functions for free. The cats documentation 还有一些您可能感兴趣的其他示例
函数等概念的最大好处之一是,泛型结构允许您从更简单的仿函数构建更复杂的类型,并保证这些复杂类型具有某些属性。可以理解,当您像您所做的那样孤立地考虑函子时,函子似乎毫无意义,但是您学习和掌握的此类构造越多,它们就会变得越来越有用。
一个更简单的例子是,几种组合函子的方法也产生了一个函子;例如,如果 List[A]
和 Option[A]
是函子,那么:
- 函子的组成:
List[Option[A]]
和 Option[List[A]]
- 函子的乘积:
(List[A], Option[A])
- 函子的总和:
Either[List[A], Option[A]]
我的知识不足以用 Scala 写出来,但在 Haskell 中,这些事实可以转化为通用代码,例如这些示例:
-- A generic type to represent the composition of any two functors
-- `f` and `g`.
newtype Compose f g a = Compose { getCompose :: f (g a) }
-- If `f` and `g` are functors, so is `Compose f g`.
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose fga) = Compose (fmap (fmap f) fga)
这是一个非常简单的例子,但是:
- 它至少作为 分析工具 已经很有用了。人们在实践中编写的 lot 数据类型,当你从这个例子的角度来看它们时,结果是更简单的函子的乘积、总和或组合。所以一旦你理解了这些结构你就可以在你写一个复杂类型时自动 "sense" 它是一个函子,以及如何写它的
map()
操作。
- 更详细的示例具有相同的风格:
- 我们有一个通用构造,它在使用实现
Functor
; 的类型实例化时保证某些契约
- 当我们向任何类型添加
Functor
实现时,我们就能够在该构造中使用该类型。
一个更详细的例子是 free monads(link 有一个扩展的 Scala 例子),一个依赖于用户提供的 Functor
s 来定义 "instructions" 的语言。其他 link(这些大多直接来自 Google 搜索):
我不懂 Scala,但在 Haskell 中,Functor
class 对定义 Van Laarhoven-style lenses:
至关重要
type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s
这些透镜通常是为特定相关类型 s
和 a
定义的,但它们与任意函子一起使用对于它们的实用性至关重要。
Functor
作为 Applicative
和 Traversable
的超级 class 的作用也很重要。在使用这些更强大的抽象时,使用 fmap
方法通常非常有用。
我们知道任何泛型类型 F[_]
withmap
方法,符合某些 laws,是一个 函子 。例如,List[_]
、Option[_]
和 F[A] = Env => A
是函子。我只是想知道这个函子抽象是否有意义。
我如何利用它们是仿函数这一事实?您能否展示一个使用 map
并且实际有用的非平凡计算示例?
好吧,一旦你知道某个东西是 Functor,你不仅会得到 map
,你还会得到所有你可以用它派生的函数
例如,可以以适用于任何仿函数的方式派生函数 lift
。
Lift 将 "lift" 函数从 A => B
到 F[A] => F[B]
对于某些 Functor F[_]
并定义为
def lift[A, B](f: A => B): F[A] => F[B] = map(_)(f)
如果您使用的库 cats or scalaz then you get these functions for free. The cats documentation 还有一些您可能感兴趣的其他示例
函数等概念的最大好处之一是,泛型结构允许您从更简单的仿函数构建更复杂的类型,并保证这些复杂类型具有某些属性。可以理解,当您像您所做的那样孤立地考虑函子时,函子似乎毫无意义,但是您学习和掌握的此类构造越多,它们就会变得越来越有用。
一个更简单的例子是,几种组合函子的方法也产生了一个函子;例如,如果 List[A]
和 Option[A]
是函子,那么:
- 函子的组成:
List[Option[A]]
和Option[List[A]]
- 函子的乘积:
(List[A], Option[A])
- 函子的总和:
Either[List[A], Option[A]]
我的知识不足以用 Scala 写出来,但在 Haskell 中,这些事实可以转化为通用代码,例如这些示例:
-- A generic type to represent the composition of any two functors
-- `f` and `g`.
newtype Compose f g a = Compose { getCompose :: f (g a) }
-- If `f` and `g` are functors, so is `Compose f g`.
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose fga) = Compose (fmap (fmap f) fga)
这是一个非常简单的例子,但是:
- 它至少作为 分析工具 已经很有用了。人们在实践中编写的 lot 数据类型,当你从这个例子的角度来看它们时,结果是更简单的函子的乘积、总和或组合。所以一旦你理解了这些结构你就可以在你写一个复杂类型时自动 "sense" 它是一个函子,以及如何写它的
map()
操作。 - 更详细的示例具有相同的风格:
- 我们有一个通用构造,它在使用实现
Functor
; 的类型实例化时保证某些契约
- 当我们向任何类型添加
Functor
实现时,我们就能够在该构造中使用该类型。
- 我们有一个通用构造,它在使用实现
一个更详细的例子是 free monads(link 有一个扩展的 Scala 例子),一个依赖于用户提供的 Functor
s 来定义 "instructions" 的语言。其他 link(这些大多直接来自 Google 搜索):
我不懂 Scala,但在 Haskell 中,Functor
class 对定义 Van Laarhoven-style lenses:
type Lens' s a = forall f . Functor f => (a -> f a) -> s -> f s
这些透镜通常是为特定相关类型 s
和 a
定义的,但它们与任意函子一起使用对于它们的实用性至关重要。
Functor
作为 Applicative
和 Traversable
的超级 class 的作用也很重要。在使用这些更强大的抽象时,使用 fmap
方法通常非常有用。