我读了article说:
为许多标准类型类[Functors]提供实例将立即为您提供许多实用免费的功能
我的问题是:你可以免费获得这个功能(对于仿函数或其他类型类)?我知道仿函数的定义是什么,但是通过将某些东西定义为仿函数/其他类型类,我可以获得 free 。除了更漂亮的语法之外的东西。理想情况下,这将是基于仿函数/其他类型类的一般和有用的函数。
我的想象(可能是错误的)自由意味着什么是这种功能:TypeClass x => useful x y = ..
==编辑/添加==
我想我主要是询问更抽象(和令人难以置信的)类型类,如this image中的类型类。对于像Ord这样不太抽象的类,我的面向对象的直觉理解。
答案 0 :(得分:9)
Functors很简单,可能不是最好的例子。让我们来看看Monads:
liftM
- 如果某些内容是Monad,则它也是liftM
为fmap
的Functor。>=>
,<=<
:您可以免费撰写a -> m b
个函数,m
是您的monad。foldM, mapM, filterM
...你得到了一堆实用函数来概括现有函数以使用你的monad。when
,guard
unless
- 您还可以免费获得一些控制功能。join
- 这实际上是monad定义的基础,但是你不需要在Haskell中定义它,因为你定义了>>=
。ErrorT
和东西。您可以将错误处理方法固定到新类型上,免费(提供或接受)!基本上,只要您将Monad
实例设置为Functor
,就可以“提升”使用新类型的各种标准函数。将它变为Applicative
和guard
也变得微不足道(但不是自动的)。
然而,这些都是更一般的想法的“症状”。您可以编写适用于所有 monad的有趣,重要的代码。您可能会发现您为类型编写的一些函数 - 无论出于何种原因,这些函数在您的特定情况下都很有用 - 可以推广到所有monad。现在你可以突然接受你的功能,并在解析器,列表,maybes和......上使用它。
*正如Daniel Fischer所指出的那样,MonadPlus
需要Monad
而不是{{1}}。
答案 1 :(得分:5)
Functors本身并不是很有趣,但它们是进入应用仿函数和Traversables
的必要踏脚石。
使应用仿函数有用的主要属性是,您可以使用fmap
与应用运算符<*>
来“提升”任何arity的任何函数以使用应用值。即您可以将a -> b -> c -> d
转换为Applicative f => f a -> f b -> f c -> f d
。您还可以查看Data.Traversable
和Data.Foldable
,其中包含几个涉及应用仿函数的通用函数。
Alternative
是一个专门的应用程序函数,它支持在“失败”的替代方案之间进行选择(“空”的确切含义取决于应用实例)。应用解析器是一个实际示例,其中some
和many
的定义非常直观(例如,匹配某些模式零次或多次或一次或多次)。
Monads是最有趣和最有用的类型类之一,但其他答案已经很好地涵盖了它们。
Monoid
是另一个既简单又立即有用的类型类。它基本上定义了一种方法,将两个数据组合在一起,然后在前面提到的concat
模块中为您提供通用Foldable
和功能,并且它还允许您使用Writer
具有数据类型的monad。
答案 2 :(得分:4)
haskell中有许多标准函数要求它们的参数实现一个或多个类型类。在代码中这样做允许其他开发人员(或您自己)以他们已经熟悉的方式使用您的数据,而无需编写其他功能。
例如,实现Ord类型将允许您使用sort,min,max等内容。否则,您将需要sortBy等。
答案 3 :(得分:4)
是的,这意味着实现类型类Foo
会为您提供免费Foo
约束的所有其他函数。
Functor
类型在这方面并不太有趣,因为它不会给你很多。
更好的例子是monad和Control.Monad
模块中的函数。在为您的类型定义了两个Monad
函数(>>=)
和return
之后,您将获得另外三十个函数,然后可以在您的类型上使用。
一些更实用的内容包括:mapM
,sequence
,forever
,join
,foldM
,filterM
,{{1 },replicateM
,when
和unless
。这些在Haskell代码中一直显示出来。
答案 4 :(得分:2)
正如其他人所说,Functor本身实际上并没有免费获得更多。基本上,类型类更高级或更通用(意味着更多的东西适合该描述),那么你将获得的“免费”功能越少。因此,例如,Functor和Monoid不会为您提供太多,但Monad和Arrow为您提供了许多免费的有用功能。
在Haskell中,为Functor和Monoid编写实例仍然是一个好主意(如果你的数据类型确实是一个仿函数或一个monoid),因为我们几乎总是在编写函数时尝试使用最通用的接口。如果您正在编写一个只能使用fmap
来操作数据类型的新功能,那么没有理由将该功能人为地限制为Monad
或Applicative
s,因为它可能在以后用于其他事情。
答案 5 :(得分:1)
如果您阅读“类型类和实例”的“接口和实现”,那么您的面向对象的直觉就会存在。如果你将新类型C作为标准类型类B的一个实例,那么你可以免费获得你的类型将适用于依赖于B的所有现有代码A.
正如其他人所说,当类型类似于Monad
时,免费赠品就是许多库函数,如foldM
和when
。