方法签名Haskell用户定义的类型

时间:2017-05-01 19:41:38

标签: haskell types

我正在尝试学习Haskell,最后我读了this 我试图弄清楚代码的某些部分是做什么的。

首先,有一个数据类型定义:

array(0) { } 
NULL 
NULL 
Link

接下来有一个功能:

infixl 4 :+:
infixl 5 :*:, :/:
infixr 6 :^:

data Expr a = Var Char
             | Const a 
             | (Expr a) :+: (Expr a) 
             | (Expr a) :*: (Expr a)
             | (Expr a) :^: (Expr a)
             | (Expr a) :/: (Expr a)
             deriving (Show, Eq)

那么,"(Num a,Eq a,Floating a)=> Expr a"在这种情况下代表什么?

" Expr的"不是构造函数,在第一行中,类型是" +(Expr Expr)",那么" a"意思是这里,为什么它被限制为双倍? 并且" a"在与#34; a"相关的类型签名中在函数的第二行,即使这里显然是一个Expr?

2 个答案:

答案 0 :(得分:3)

在数据定义中

data Expr a = ...

a表示那里有一个类型变量。一个简单的例子是

data Two a = Two a a

这是一个名为Two的类型,它采用单个类型参数。它有一个名为Two的数据构造函数,它有两个字段,每个字段都是a。例如,类型Two Int具有专门的构造函数Two :: Int -> Int -> Two Int

在这种情况下,您说您的Expr类型具有类型参数,并且具有许多构造函数,其中一些构造函数具有类型a的字段。您可以使用此值来设置Expr Int类型的值,例如Const 1 :+: Const 2

当您看到类似

的类型签名时
simplify :: (Num a, Eq a, Floating a) => Expr a -> Expr a

这意味着该函数采用类型Expr a的值并返回相同类型的值,除非此处类型变量a具有其他约束。即NumEqFloating。这些是类型类,类型a必须实现这些类型类才能在simplify上使用Expr a

类型签名中的aa定义的第一行中的simplify无关。作者只能选择使用相同的名称。类型名称和数据名称存在于Haskell中完全不同的名称空间中,它们根本不冲突或相关。

答案 1 :(得分:1)

对于具有类型aNumEq实例的每个类型Floatingsimplify可以专门用于Expr a -> Expr a。类型和值的名称空间是分开的。 Expr是一个类型构造函数。 Expr a是具有值的类型。此处的任何内容都不限于Double(+)会使用Num个实例承认所有内容。