我正在尝试学习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?
答案 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
具有其他约束。即Num
,Eq
和Floating
。这些是类型类,类型a
必须实现这些类型类才能在simplify
上使用Expr a
。
类型签名中的a
与a
定义的第一行中的simplify
无关。作者只能选择使用相同的名称。类型名称和数据名称存在于Haskell中完全不同的名称空间中,它们根本不冲突或相关。
答案 1 :(得分:1)
对于具有类型a
,Num
和Eq
实例的每个类型Floating
,simplify
可以专门用于Expr a -> Expr a
。类型和值的名称空间是分开的。 Expr
是一个类型构造函数。 Expr a
是具有值的类型。此处的任何内容都不限于Double
,(+)
会使用Num
个实例承认所有内容。