Haskell中不同类型之间的关系

Posted

技术标签:

【中文标题】Haskell中不同类型之间的关系【英文标题】:Relation Between the Different Types in Haskell 【发布时间】:2018-10-31 23:46:44 【问题描述】:

据我了解,Haskell 有 4 种“类型”:

代数数据类型data 数据类型构造函数(data 类型中的 = 之后的内容;技术上不是类型,我不认为) 使用type 键入别名 带有class 的类型类 使用instance 键入实例

问题是:

    如果 Haskell 中有更多种类的类型。如果有,有什么关系。 data 类型和class 类型类之间有什么区别。它们看起来很相似,但显然它们有一些不同的特征。与 (3) 相同。 data 类型和 instance 类型类实例之间有什么区别。

我是 Haskell 的新手。

【问题讨论】:

数据类型构造函数不是类型。它是一个“值”,因此比类型低一级。 classinstance 相同。我认为有点遗憾的是,Haskell 的命名法与大多数命令式编程语言非常相似,但实际上有一些非常不同的含义。 【参考方案1】:

datanewtype 引入了新类型(或实际上是类型构造函数 - Maybe 不是类型,但 Maybe a 是任何 a 的类型)。

data 声明引入了新类型(= 的左侧)和表示该类型数据的方法(= 的右侧)。

例如,如果您有这样的数据声明:

data SomeType = SomeConstructor

然后你引入了一个名为SomeType的新类型,以及一种构造SomeType值的方法,即构造函数SomeConstructor(顺便说一句,它没有任何参数,所以唯一的值包含在这个类型)。

类型类不做这些事情任何一个instance 也不做)。一个类型类引入了一个 约束 和一堆多态函数,如果满足该约束,这些函数应该可用。 instance 基本上是通过为这些函数提供实现来表示“这种类型符合这个约束”。所以class 并不是真正引入新类型,它只是为现有类型提供临时多态性的一种方式。

例如,Show 类型类大致是这样的:

class Show a where -- a is an instance of Show if
   show :: a -> String -- it has a function called show with this signature

(请注意,Prelude 中的实际 Show 类并不看起来像这样)

show 现在具有 Show a => a -> String 类型,您可以将其解读为

对于所有 a,如果它们满足约束 Show(或者,如果它们是 Show 的实例),这是一个接受 a 并返回字符串的函数

这样的一个实例看起来像这样

instance Show SomeType where
  show SomeConstructor = "SomeConstructor"

这意味着

SomeType 满足约束Show,我将通过提供show 的实现来向您展示如何实现

这大概就是它的要点。有一些语言扩展允许类型类和实例发生更多涉及的事情,但您现在不必担心。

【讨论】:

在带有ConstraintKinds 的 GHC Haskell 中,类型类确实以某种方式引入了新类型,不是针对普通类型(类型为 *)而是针对约束; class Num a where … ; class Functor f where … 创建类型构造函数 Num :: * -> ConstraintFunctor :: (* -> *) -> Constraint。约束仍然是类型,只是没有值。【参考方案2】:

您可能听说过 kinds,它们是 Haskell 中的“类型的类型”。类型是一种类型为* 的东西,它表示可以有值的东西:

> :kind Int
Int :: *
> :kind Char
Char :: *

类型构造函数是类型为* -> * 的东西;类型构造函数接受一个类型(* 之类的东西)并返回另一种类型。

> :kind Maybe
Maybe :: * -> *
> :kind []
[] :: * -> *

应用类型构造函数为您提供了一种新事物*

> :kind Maybe Int
Maybe Int :: *
> :kind [] Float
[] Float :: *

(解析器允许[Foo] 作为[] Foo 的特例。)

还有其他种类的东西。其中之一是Constraint,您可以使用约束构造函数(也称为类型类)创建Constraint。给一个约束构造函数一个类型,你就会得到一个约束。

> :kind Show
Show :: * -> Constraint
> :kind Show Int
Show Int :: Constraint
> :kind Show (Int -> Char)
Show (Int -> Char) :: Constraint

(请注意,即使没有定义 Int -> Char 的实例,后者也是正确的。)


从这个角度来看,=> 看起来像一个运算符,而不仅仅是特殊的语法。它的参数是一个约束的“列表”(尽管使用普遍量化的类型变量而不是具体类型)和一个类型,它的返回值是一个“约束”类型(假设除了@987654336 之外还有一种ConstrainedType @、* -> *Constraint)。

:t show
show :: Show a => a -> String

-- Taking extreme liberties with syntax
-- :k (=>)
-- (=>) :: [Constraint] -> * -> ConstrainedType
-- A section?
-- :k (Show a =>)
-- (Show a =>) :: * -> ConstrainedType
-- :k (Showa => * -> String)
-- Show a => a -> String :: ConstrainedType

【讨论】:

以上是关于Haskell中不同类型之间的关系的主要内容,如果未能解决你的问题,请参考以下文章

Haskell:在 ByteStrings 和不同的文本编码之间进行转换

如何使用haskell类型系统来描述关系,从而防止出现更多错误

Rust闭包和Haskell lambda有什么区别? [关闭]

如何在 Javascript 中实现 Haskell 的 FRP Behavior 类型?

Haskell中的两个无限数据结构之间是不是可以进行相等测试?

未装箱类型和严格性之间有啥关系?