10

我听说 Haskell 被描述为具有结构类型。据我了解,记录是一个例外。例如,即使它们的字段在名义上有所不同,也不foo能用某种类型来调用。HRec2HRecHRec2

data HRec = HRec { x :: Int, y :: Bool }
data HRec2 = HRec2 { p :: Int, q :: Bool }

foo :: HRec -> Bool

是否有一些解释拒绝将结构类型扩展到包括记录在内的所有内容?

即使对于记录,是否存在具有结构类型的静态类型语言?对于所有静态类型的语言,我是否可以阅读有关这方面的一些争论?

4

4 回答 4

16

Haskell 有结构化类型,但没有结构化类型,这不太可能改变。*

拒绝允许名义上不同但结构相似的类型作为可互换的参数被称为类型安全。这是一件好事。Haskell 甚至有一个 newtype 声明来提供只是名义上不同的类型,以允许您强制执行更多类型安全。类型安全是一种尽早发现错误的简单方法,而不是在运行时允许它们。

除了 amindfv 的好答案(包括通过类型类的临时多态性(实际上是程序员声明的功能等效性))之外,还有参数多态性,您绝对允许任何类型,因此[a]允许列表中的BTree a任何类型并允许二叉树中的任何类型。

这给出了“这些类型可以互换吗?”的三个答案。

  1. 不; 程序员没有这么说。
  2. 等效于特定目的,因为程序员是这样说的。
  3. 不在乎 - 我可以对这个数据集合做同样的事情,因为它不使用数据本身的任何属性。

没有 4:编译器推翻了程序员,因为他们碰巧在其他函数中使用了几个 Int 和一个 String。

*我说 Haskell 不太可能改用结构化类型。有一些讨论会介绍某种形式的可扩展记录,但没有计划将(Int,(Int,Int))计数(Int, Int, Int)与.Triple {one::Int, two::Int, three::Int}Triple2 {one2::Int, two2::Int, three2::Int}

于 2014-01-12T10:05:31.717 回答
10

Haskell 记录实际上并不比类型系统的其他部分“结构更少”。每种类型要么完全指定,要么“特别模糊”(即用类型类定义)。

要同时允许HRecHRec2to f,您有几个选择:

代数类型:

在这里,您定义HRecHRec2记录都成为HRec类型的一部分:

data HRec = HRec  { x :: Int, y :: Bool }
          | HRec2 { p :: Int, q :: Bool }

foo :: HRec -> Bool

(或者,也许更惯用:)

data HRecType = Type1 | Type2
data HRec = HRec { hRecType :: HRecType, x :: Int, y :: Bool }

类型类

在这里,您定义foo为能够接受任何类型作为输入,只要已为该类型编写了类型类实例:

data HRec  = HRec  { x :: Int, y :: Bool }
data HRec2 = HRec2 { p :: Int, q :: Bool }

class Flexible a where
   foo :: a -> Bool

instance Flexible HRec where
   foo (HRec a _) = a == 5 -- or whatever

instance Flexible HRec2 where
   foo (HRec2 a _) = a == 5

使用类型类可以让你比常规的结构类型走得更远——你可以接受嵌入了必要信息的类型,即使这些类型表面上看起来并不相似,例如:

data Foo = Foo { a :: String, b :: Float }
data Bar = Bar { c :: String, d :: Integer }

class Thing a where
   doAThing :: a -> Bool

instance Thing Foo where
    doAThing (Foo x y) = (x == "hi") && (y == 0)

instance Thing Bar where
    doAThing (Bar x y) = (x == "hi") && ((fromInteger y) == 0)

我们可以运行fromInteger(或任何任意函数)从我们拥有的数据中获取我们需要的数据!

于 2014-01-12T07:12:00.643 回答
2

我知道 Haskell 中结构类型记录的两个库实现:

HList较旧,并在一篇出色的论文中进行了解释:Haskell's overlooked object system(在线免费,但不允许我包含更多链接)

乙烯基更新,并使用花哨的新 GHC 功能。至少有一个图书馆,vinyl-gl,在使用它。

不过,我无法回答您问题的语言设计部分。

于 2014-01-13T15:01:59.490 回答
1

要回答您的最后一个问题,Go 和 Scalas 肯定有结构类型。有些人(包括我)会称之为“静态不安全类型”,因为它隐式声明程序中所有同名的方法具有相同的语义,这意味着“远处的诡异动作”,将源文件中的代码与程序从未见过的某些库中的代码。

IMO,最好要求同名方法明确声明它们符合行为的命名语义“模型”。

是的,编译器会保证该方法是可调用的,但它并不比说:

 f :: [a] -> Int

并让编译器选择一个可能是也可能不是的任意实现length

(使用 Scala“隐式”或 Haskell(GHC?)“反射”包可以使类似的想法变得安全。)

于 2014-01-13T16:29:24.363 回答