如何在Haskell中进行泛型编程? < C++ >,我发现泛型编程必不可少。我想知道哈斯凯尔的人是怎么做到的

如何在Haskell中进行泛型编程? < C++ >,我发现泛型编程必不可少。我想知道哈斯凯尔的人是怎么做到的,haskell,generic-programming,Haskell,Generic Programming,说如何在Haskell中编写通用交换函数 Haskell中是否有一个相当于部分专门化的概念 在C++中,我可以部分地为通用映射函数专门化泛型交换函数,它具有用于O(1)容器交换的特殊交换方法。您在Haskell中是如何做到这一点的,或者Haskell中泛型编程的典型示例是什么?这与您关于Haskell和quicksort的另一个问题密切相关。我想你至少需要读一本关于哈斯克尔的书的介绍。听起来好像你还没有抓住它的关键点,那就是它禁止你修改现有变量的值 交换(正如在C++中理解和使用的)本质上就是修

说如何在Haskell中编写通用交换函数

Haskell中是否有一个相当于部分专门化的概念


在C++中,我可以部分地为通用映射函数专门化泛型交换函数,它具有用于O(1)容器交换的特殊交换方法。您在Haskell中是如何做到这一点的,或者Haskell中泛型编程的典型示例是什么?

这与您关于Haskell和quicksort的另一个问题密切相关。我想你至少需要读一本关于哈斯克尔的书的介绍。听起来好像你还没有抓住它的关键点,那就是它禁止你修改现有变量的值

交换(正如在C++中理解和使用的)本质上就是修改现有值。这样我们就可以使用一个名称来引用一个容器,并用完全不同的内容替换该容器,并将该操作专门化为对特定容器的快速(且无异常),从而允许我们实现修改和发布方法(对于编写异常安全代码或尝试编写无锁代码至关重要)

您可以在Haskell中编写一个通用交换,但它可能需要一对值,然后返回一对包含相同值且位置颠倒的新值,或者类似的内容。其实不一样,也没有相同的用途。通过在映射内部挖掘并交换其单个成员变量来专门化映射是没有任何意义的,因为在Haskell中不允许这样做(可以专门化,但不能修改变量)

假设我们想在Haskell中“测量”一个列表:

measure :: [a] -> Integer
这是一个类型声明。这意味着函数
measure
获取任何内容的列表(
a
是一个泛型类型参数,因为它以小写字母开头),并返回一个整数。因此,这是一个任何元素类型的列表——它是C++中的函数模板,或者是Haskell中的多态函数(与C++中的多态类不一样)。 我们现在可以通过为每个有趣的案例提供专门化来定义:

measure [] = 0
i、 e.测量空列表,得到零

这里有一个涵盖所有其他情况的非常通用的定义:

measure (h:r) = 1 + measure r
LHS上括号中的位是一种模式。它的意思是:拿一张单子,把头折下来,称之为h,把剩下的部分称为r。这些名称就是我们可以使用的参数。这将匹配至少有一项的任何列表


<>如果你在C++中尝试过模板元编程,这对你来说都是老帽子,因为它涉及完全相同的样式——递归做循环,专门化使递归终止。除了在Haskell中它是在运行时工作的(函数对特定值或值模式的专门化)。

正如Earwicker所说,这个例子在Haskell中没有那么重要。如果你绝对想拥有它,这里有一个类似的东西(交换一对的两部分),c&p来自一个交互式会话:

GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
Loading package base ... linking ... done.
Prelude> let swap (a,b) = (b,a)
Prelude> swap("hello", "world")
("world","hello")
Prelude> swap(1,2)
(2,1)
Prelude> swap("hello",2)
(2,"hello")

在哈斯克尔的书中读了足够多的内容,真正理解了埃尔威克的答案之后,我建议你也读一读关于类型类的书。我不确定“部分专门化”是什么意思,但听起来它们可能很接近。

在Haskell中,函数尽可能通用(多态)-编译器将推断“最通用的类型”。例如,在没有类型签名的情况下,Marko的示例交换在默认情况下是多态的:

*Main>let swap(a,b)=(b,a)
*Main>:t交换
互换:(t,t)->(t,t)

至于部分专业化,ghc有一个非98扩展:

另外,请注意术语上存在不匹配。在C++中,泛型被称为泛型,在java语言中称为多态。Haskell中的“Generic”通常指多型:

但是,在上面我使用C++的泛型含义。p> 在Haskell中,您可以创建类型类。类型类与OO语言中的类不同。以Numeric类型类为例,它表示该类的任何实例都可以执行某些操作(+-*/),因此Integer是Numeric的一个成员,提供了视为Numeric所必需的函数的实现,并且可以在任何需要Numeric的地方使用

假设您希望能够foo int和string。然后将Int和String声明为 类型类Foo的实例。现在,只要看到类型(fooa),就可以使用Int或String


之所以不能直接添加INTS和浮点,是因为Addio有类型(数字A)A~>A--> A是一个类型变量,就像普通变量一样,它只能绑定一次,所以一旦绑定到int,列表中的每一个都必须是int。< /P> SWAP是典型的C++ GP示例。您也可以尝试用一个规范的Haskell示例来说明相同的概念。我修改了这个问题以反映这一点。除了关于泛型编程和部分专业化(查找咖喱)的奇怪问题外,“交换变量”的问题也很奇怪:Haskell中没有“交换两个盒子的内容”这样的东西,因为Haskell中的变量不是包含数据的盒子。我仍在努力理解这个问题,因为Haskell的全部优点是它允许您以最通用的方式编写函数。。。也许你至少应该读一读“为什么函数式编程很重要”这篇论文@史莱瓦沙尔:大体上,这是对的,但并不完全正确。在标准Haskell中不能做的一种泛型编程,但C++中可以使用数字来创建参数类型。C++允许您通过整数常量表达式参数化类型,它可以是递归的,从而允许任意计算。