Functors或其他类型类可以免费获得哪些功能?

11

我阅读了一篇文章,其中提到:

为许多标准类型类[FUNCTOR]提供实例将立即为您免费提供许多功能

我的问题是:通过将某些东西定义为functor /其他类型类,我可以获得什么样的免费功能?我知道functor的定义,但除了更漂亮的语法之外,我能获得什么免费服务。理想情况下,这将是在操作functor /其他类型类上通用且有用的函数。

我想象中(可能不正确)的“免费”意味着以下类型的功能:TypeClass x => useful x y = ..

==编辑/添加==

我想主要询问更抽象(令人头疼的)类型类,比如此图像中的类型类,对于像Ord这样不太抽象的类,我的面向对象直觉可以理解。

6个回答

9
Functors很简单,可能不是最好的例子,我们来看看Monads:
- `liftM` - 如果某个东西是Monad,它也是一个Functor,其中`liftM`就是`fmap`。 - `>>=`和`<=<`:你可以免费组合`a -> m b`函数,其中`m`是你的monad。 - `foldM`、`mapM`、`filterM`等等...你会得到一堆实用程序函数,将现有函数泛化为使用你的monad。 - `when`、`guard`*和`unless` - 你还免费获得一些控制函数。 - `join` - 实际上这对于定义monad相当基础,但你不需要在Haskell中定义它,因为你已经定义了`>>=`。 - transformers - `ErrorT`等等。你可以免费(或者说付出一些代价)将错误处理附加到你的新类型上。
基本上,只要你将其定义为`Monad`实例,你就可以获得各种标准函数“提升”以使用你的新类型。它也变得微不足道(但不幸的是不是自动的)使它成为Functor和Applicative。
然而,这些都是更普遍的想法的“症状”。您可以编写适用于所有monads的有趣且非平凡的代码。您可能会发现,您为自己的类型编写的一些函数 - 由于某种原因在您特定的情况下有用 - 可以泛化为所有monads。现在,您可以突然将您的函数应用于解析器、列表、可能性等等。
*正如Daniel Fischer所指出的那样,`guard`需要`MonadPlus`而不是`Monad`。

5
guard 需要 MonadPlus - Daniel Fischer
由于这样的库函数似乎只有少数几个,即使对于相当丰富的类型类monad而言也是如此,我得出结论认为这不太可能发生。从理论上讲,你的代码可能会神奇地概括到所有monads,但实际上,如果它们存在,我会看到更多免费的有用函数适用于monads。 - user1138184

5
Functors本身并不是非常有趣,但它们是进入应用函子和Traversables的必要基石。
使应用函子变得有用的主要属性是您可以使用应用操作符<*>fmap来将任何元数的函数“提升”以适用于应用值。也就是说,您可以将任何a -> b -> c -> d转换为Applicative f => f a -> f b -> f c -> f d。您还可以查看Data.TraversableData.Foldable,它们包含几个涉及应用函子的通用函数。

Alternative是一种特殊的应用函子,支持在可能“失败”的备选项之间进行选择(“空”确切含义取决于应用函子实例)。应用函子解析器是一个很好的实际例子,其中somemany的定义非常直观(例如,匹配某个模式零次或多次或一次或多次)。

单子是最有趣和最有用的类型类之一,但已经有其他答案详细介绍了它们。

Monoid是另一个既简单又立即有用的类型类。它基本上定义了一种将两个数据合并在一起的方式,这样就可以获得一个通用的concat以及在前面提到的Foldable模块中的功能,并且它还使您能够使用Writer单子与数据类型一起使用。


4

在Haskell中,许多标准函数需要它们的参数实现一个或多个类型类。在您的代码中这样做,可以使其他开发人员(或者您自己)以已经熟悉的方式使用您的数据,而无需编写额外的函数。

例如,实现Ord类型类将允许您使用诸如sort、min、max等功能。否则,您需要使用sortBy等函数。


4

是的,这意味着实现类型类Foo会为你提供所有其他具有Foo约束的函数“免费”使用。

Functor类型类在这方面并不太有趣,因为它没有给你很多东西。

一个更好的例子是单子和Control.Monad模块中的函数。一旦你为你的类型定义了两个Monad函数(>>=)return,你就可以使用另外30多个函数来处理你的类型。

其中一些更有用的函数包括:mapMsequenceforeverjoinfoldMfilterMreplicateMwhenunlessliftM。这些函数在Haskell代码中经常出现。


2
正如其他人所说,Functor本身并没有为您提供太多免费的功能。基本上,类型类越高级或通用(意味着更多的事物符合该描述),那么您将获得的“免费”功能就越少。因此,例如,Functor和Monoid并没有为您提供太多,但是Monad和Arrow会为您提供许多有用的免费功能。
在Haskell中,如果您的数据类型确实是functor或monoid,则编写Functor和Monoid实例仍然是一个好主意,因为我们几乎总是尝试使用最通用的接口来编写函数。如果您正在编写一个新函数,它只能使用fmap来操作您的数据类型,那么没有理由将该函数人为地限制为Monad或Applicative,因为稍后可能会对其他事物有用。

1

如果你将“接口和实现”替换为“类型类和实例”,那么你的面向对象直觉就可以延续下去。如果你将新类型C作为标准类型类B的一个实例,那么你就可以免费获得你的类型能够与所有依赖于B的现有代码A一起使用的功能。

UML diagram

正如其他人所说,当类型类是像Monad这样的东西时,那么免费赠品就是许多库函数,例如foldMwhen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接