什么是函数式编程中的代数结构?

What are algebraic structures in functional programming?

我一直在简单阅读函数式编程的概念和想法。到目前为止,一切顺利,我已经阅读了三个主要概念:代数结构、类型 类 和代数数据类型。我对什么是代数数据类型有很好的理解。我认为总和类型和产品类型相当简单。例如,我可以想象创建一个代数数据类型,如 Card 类型,它是由两个枚举类型组成的产品类型,Suit(具有四个值和符号)和 Rank(具有13 个值和符号)。

但是,我仍然无法准确理解什么是代数结构和类型 类。我脑子里只有一张表面图,但不能完全理解,例如,不同类型的代数结构,如仿函数、幺半群、单子等。它们究竟有何不同?如何在编程环境中使用它们?类型 类 与常规 类 有何不同?谁能至少给我指出一本关于抽象代数和函数式编程的好书的方向?有人建议我学习 Haskell 但我真的需要学习 Haskell 才能理解函数式编程吗?

你在这里问了很多问题,但我会尽力回答:

… different types of algebraic structures like functors, monoids, monads, etc. How exactly are these different? How can they be used in a programming setting?

这是学习时很常见的问题Haskell。我不会在这里写 另一个 答案——而且一个完整的答案相当长——但是一个简单的 Google 搜索给出了一些非常好的答案:例如我可以推荐1 2 3

How are type classes different from regular classes?

(我假设“常规 classes”指的是 OOP 中的 classes。)

这是另一个常见问题。基本上,除了名字之外,两者几乎没有任何共同点。 OOP 中的 class 字段 方法 的组合。 类 通过创建 class 的 个实例 使用;每个实例都可以在其字段中存储数据,并使用其方法操作该数据。

相比之下,类型 class 只是函数的集合(通常也称为 方法 ,尽管几乎没有任何联系)。您可以通过重新定义该类型的 class 的每个方法来为数据类型声明类型 class 的 instance(同样,无连接),之后您可以使用该类型的方法。例如,Eq class 看起来像这样:

class Eq a where
    (==) :: a -> a -> Bool
    (/=) :: a -> a -> Bool

并且您可以通过实现每个函数为 Bool 定义 class 的实例:

instance Eq Bool where
    True == True   = True
    False == False = True
    _ == _         = False

    p /= q = not (p == q)

Can anyone at least point me in the direction of a good book on abstract algebra and functional programming?

我必须承认我对此无能为力(而且对于 Stack Overflow 来说它是 off-topic)。

Someone recommended I learn Haskell but do I really need to learn Haskell in order to understand functional programming?

不,你不需要——你可以从任何函数式语言学习函数式编程,包括 Lisp(特别是 Scheme 方言)、OCaml、F#、Elm、Scala 等。Haskell 恰好是一种特别的 '纯函数式编程语言,我也会推荐它,但如果你只是想学习和理解函数式编程,那么其中任何一种都可以。

"algebraic structure"是一个远远超出编程的概念,它属于数学。

想象一下所有可能的数学对象的深不可测的深海。每个条纹的编号(naturals, the reals, p-adic numbers...) are there, but also things like sequences of letters, graphs, trees, symmetries of geometrical figures,以及它们之间的所有 well-defined 转换和映射。还有很多。

我们可以尝试通过指定条件向大海“撒网”并仅保留其中的一些实体。就像“事物的集合,其中有一个操作将其中两个事物组合成同一类型的第三个事物,并且该操作是关联的”。我们可以为这些条件赋予它们自己的名称,比如 "semigroup"。 (因为我们谈论的是高度抽象的东西,所以很难选择一个描述性的名称。)

这遗漏了数学“海”中的许多居民,但描述仍然符合其中的大部分!许多事物的集合是半群。例如具有乘法运算的自然数,还有 non-empty 字母列表与连接,或 symmetries of a square with composition.

您可以使用额外的条件来扩展您的描述。就像“一个半群,还有一个元素使得它与任何其他元素组合得到另一个元素,不变”。这限制了符合描述的数学实体的数量,因为你要求更多。一些有效的半群将 lack that "neutral element". But a lot of mathematical entities will still satisfy the expanded description. If you aren't careful, you can declare conditions so restrictive that no possible mathematical entity can actually fit them! At other times, you can be so precise that only one 实体适合它们。

纯粹使用这些数学实体的描述,仅使用我们需要的一般属性,我们可以获得半群运算的 unexpected results about them, non-obvious at first sight, results that will apply to all entities which fit the description. Think of these discoveries as the mathematical equivalent of "code reuse". For example, if we know that some collection of things is a semigroup, then we can calculate exponentials using binary exponentiation instead of tediously combining a thing with itself n times. But that only works because of the associative property