Haskell 如何获取给定多态函数和表达式的类型?

Haskell 如何获取给定多态函数和表达式的类型?,haskell,typing,Haskell,Typing,以下是提示此帖子的考试问题: 试题: 考虑Haskell中二叉树的以下定义 data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a) flatten Empty = [ ] flatten (Leaf l) = [l] flatten (Node t1 r t2) = (flatten t1) ++ (r : (flatten t2)) 根据该声明,树可以是:Empty、包含a类型元素的叶、或包含a类型元素的节点和两个树s 例如,以下表达

以下是提示此帖子的考试问题:

试题: 考虑Haskell中二叉树的以下定义

data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)
flatten Empty = [ ]
flatten (Leaf l) = [l]
flatten (Node t1 r t2) = (flatten t1) ++ (r : (flatten t2))
根据该声明,树可以是:
Empty
、包含
a
类型元素的
、或包含
a
类型元素的
节点和两个
s

例如,以下表达式具有类型
树Int

Leaf 0

Node (Leaf 1) 2 (Leaf 3)
下面的函数将
展平为元素列表(回想一下,
++
是Haskell中列表的串联运算符)

一,。为函数
flatten
提供多态类型。证明你的答案是正确的

二,。为表达式指定一个类型:

证明你的答案是正确的

我的问题 我想我理解这里的理论,很明显,
展平
,为了完成它的工作,接受多种类型(
[]
节点
),但我应该如何从中解释它的类型呢?除非我假设
flatte
与它接受的类型相同,否则我不确定从这里开始该怎么做

关于问题的第二部分,
flatte
是否有不同的类型取决于它是否以表达式的形式出现?如果是这样的话,我觉得我在最后一段中的假设是正确的,但我希望我能从实际的逻辑中得到安慰,而不仅仅是猜测

提前谢谢

很明显,
flatten
,为了完成它的工作,它接受多种类型(
[]
Leaf
节点

我不明白你为什么认为
flatten
接受
[]
。我甚至不知道你这是什么意思
[]
不是一个类型,它是一个类型构造函数,它将类型
a
作为参数,并返回类型
[a]
“其元素类型为
a
”的列表

定义
plant
的三个子句都使它成为一个接受一个参数的函数,因此它的类型为
x->y
,其中
x
是参数的类型,
y
是返回类型。在每种情况下,参数都是通过应用
类型构造函数的构造函数形成的,因此参数的类型为
树w
。第一个子句中的返回值是
[]
,因此其类型为
[z]
。到目前为止,我们知道最常见的
flatten
类型是
树w->[z]
。第二个子句
flatten(Leaf l)=[l]
提供了一个额外的约束
w=z
,因为
l
的类型出现在两侧,所以最常见的类型是
树z->[z]

这实际上是
展平
的有效类型,因此
树z->[z]
展平
的最通用类型。要看到这一点,您需要浏览整个定义,并检查它是否没有对
z
施加任何附加约束

这是一个多态类型:它包含类型变量
z
。此变量可以由任何类型实例化。例如,
flatten(Leaf(1::Int))
对类型
树Int->[Int]
使用
flatten
,而
flatten(Leaf True)
对类型
树Bool->[Bool]
使用
flatten

事实上,
flatten
是多态的,并不是因为它是一个函数。将其应用于参数不会改变展平的类型,但它可能不会完全通用地使用它。结果表达式的类型仍然可以是多态的。例如,对于所有
a
\x->flatten x
的类型是
树a->[a]
,与
flatten
相同,这并不奇怪,因为
\x->flatten x
等同于
flatten


flant(Leaf 3)
的类型来自三个约束:
flant
的参数类型为
树a
的返回类型为
[a]
Leaf
接受任何类型
a
并返回
树a
,而
3
的返回类型为
Num a=>a
,即,
3
具有任何类型
a
,前提是该类型是
Num
类的实例。因此,
flatten(叶3)
具有类型
[a]
,在约束条件下,
a
Num
的一个实例,即
flatten(叶3)
具有最通用的类型
Num a=>[a]
要正确理解这个问题,您应该知道 和。Haskell使用类型推断算法,但由于试题的知识是不必要的,而且直觉是充分的,所以试题的措辞是合理的。如果您在GHCI中键入
:t
,它将为您提供类型,这一点也很有用

在此特定示例中,您的定义创建了四个构造函数-一元类型构造函数
、空数据
、一元数据
、三元数据
节点

现在,我们来看看函数。函数有三个基于模式匹配的定义,但是我们知道每个定义必须具有相同的类型(或者可以与其他类型统一)。从第一行开始

flatten Empty = [ ]
我们可以看到,flatte获取一些
空的
(我们知道的是一个
的数据构造函数),并返回一个
[]
,即一个列表。但是,
是参数化类型<代码>空
但是不使用参数化,因此它可以属于任何
-一个polymorfous类型
树a
[]
是一个列表。列表通常为
[a]
类型,
a
是列表的成员类型。没有成员
flatten Empty = [ ]
flatten Empty = ['e']
flatten (Leaf l) = [l]
flatten (Node t1 r t2) = (flatten t1) ++ (r : (flatten t2))