Haskell 类型同义词声明可能有约束?

标签 haskell types polymorphism constraints

假设我想为所有带有 Int 的列表创建一个类型同义词。

我可以:

type NumberList = [Int]

但是如果我想调用所有包含数字 NumberList 的列表呢?我如何设置约束并说只要“Num a”的所有[a]都应该被称为相同的?

编辑::看到我重新思考的答案后。似乎我违背了 Haskell 背后的一个基本理念,而且返回相对较小(只是形式上的问题)。我决定这样做:如果一个类型需要两个彼此相同但仅在 Int 或 Float 上不同的实例,那么它们之间的差异太小,无法保证完成使用 Int 和 Float 所需的解决方法,但调用它们是同一件事,这就是为什么我必须将使用限制在其中之一。但是,如果我应该同时拥有两者有一个重要原因,那么我可能可以在实例名称中反射(reflect)这个重要原因,从而通过以下方式避免问题:
data Thing = Thing_A(String, String Float) | Thing_B(String,String,Int)

---因此坚持使用 Haskell 的类型系统并且仍然接受它们作为数据类型 Thing。一开始我想做的是
data Thing = Thing(String, String, Float) | Thing(String, String, Int)

最佳答案

这对应于存在量化。在伪 Haskell 中,

type NumberList = exists a . Num a => [a]

我说“伪”是因为 GHC 不允许动态引入存在量词——您需要为此创建一个单独的数据类型。

现在,您将在箭头左侧使用 NumberList 的大多数类型,其中 «exists» 有效地将其含义更改为 «forall»。

也就是说,而不是写
isIncreasing :: NumberList -> Bool

这与
isIncreasing :: (exists a . Num a => [a]) -> Bool

你可以写
isIncreasing :: forall a . Num a => [a] -> Bool

或者干脆
isIncreasing :: Num a => [a] -> Bool

当然,拥有类型同义词似乎代码更少,但它也有缺点。
顺便说一下,这些缺点对于基于存在方法的面向对象编程来说是典型的。

例如,您想要连接两个列表。通常你会写
(++) :: forall a . [a] -> [a] -> [a]

(这里再次 forall 是不必要的,为了清楚起见添加了)。由于a在整个签名中是相同的,以确保您连接相同类型的列表。

我们如何连接两个数字列表?一个签名
(++) :: NumberList -> NumberList -> NumberList

行不通,因为一个列表可能包含 Ints,而另一个列表可能包含 Doubles。生成的 NumberList 必须包含单一类型的值。

或者,比如说,您想找到列表元素的总和。

通常你写
sum :: Num a => [a] -> a

请注意,结果类型与列表元素的类型相同。唉,我们不能对 NumberList 做同样的事情!
sum :: NumberList -> ???

结果类型是什么?我们也可以在那里应用存在量化。
sum :: NumberList -> (exists a . Num a => a)

但是现在原始列表类型和 sum 类型之间的联系丢失了——至少对于 Haskell 的类型系统来说是这样。如果您随后决定编写一个函数,例如
multiplySum :: Integer -> [Integer] -> Integer
multiplySum x ys = x * sum ys

那么你会得到一个类型错误,因为 sum ys可以是任何类型,不一定是 Integer 类型。

如果你把所有东西都推到极致,让每一种类型都存在量化,这会奏效——但你最终会得到另一种类似面向对象的语言,但它们的所有问题都存在。

(也就是说,存在量化有一些很好的用例,当然。)

关于Haskell 类型同义词声明可能有约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12717301/

相关文章:

c++ - 为什么我们实际上需要运行时多态性?

c++ - 如何在使用继承和虚拟运算符()的系统中使用 odeint 求解器

Haskell类型的具体数据构造函数

java - Java中long,double,byte,char的目的是什么?

java - 如何使用 BigInteger 类在 Java 中实现无符号 64 位 int?

go - 即使接口(interface)相同,也不能将类型 X 用作类型 Y

haskell - ghc-gc-tune 0.2.1 可以与 ghc 7.4.1 一起使用吗?

vim - Vim 中令人恼火的 Tab 问题,在 Haskell 中

arrays - 如何将 `getBounds' 与 STArray 一起使用?

haskell - 什么是单态性限制?