此图片中F的多种类型?
https://youtu.be/bre_dyedgm0?t=1362
data T a where
T1 :: Bool -> T Bool
T2 :: T a
f x y = case x of
T1 x -> True
T2 -> y
Simon在f 可以键入t a - > a - >一个
,但我认为返回值必须是一个布尔,因为这是案例表达式分支的明确结果。这是关于Haskell Gadts的。为什么这样?
https://youtu.be/brE_dyedGm0?t=1362
data T a where
T1 :: Bool -> T Bool
T2 :: T a
f x y = case x of
T1 x -> True
T2 -> y
Simon is saying that f
could be typed as T a -> a -> a
, but I would think the return value MUST be a Bool since that is an explicit result in a branch of the case expression. This is in regards to Haskell GADTs. Why is this the case?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是Gadts的重点。在构造函数上匹配可以导致其他类型的信息范围。
让我们看一下GHC检查以下定义时会发生什么:
让我们首先查看
t2
案例,只是为了使其脱离。y
,结果具有相同的类型,t2
是多态的,因此您可以声明其类型也是t a
。一切都很好。然后是更棘手的情况。请注意,我删除了
case
内的名称x
的绑定,因为阴影可能会令人困惑,不使用内部值,并且不会更改任何内容解释。当您在GADT构造函数上匹配t1
(明确设置类型变量)时,它会在该分支中引入其他约束,从而添加该类型信息。在这种情况下,匹配t1
介绍了(a〜bool)
约束。这种类型的平等说a
和bool
相互匹配。因此,具有字体true
带有类型bool
匹配a
在类型签名中匹配。y
不使用,因此该分支与t a - > a - >
。所以一切都匹配了。
t a - > a - >
是该定义的有效类型。但是正如西蒙所说的那样,这是模棱两可的。t a - >布尔 - > bool
也是该定义的有效类型。两个都不是另一个更一般的,因此定义没有原理类型。因此,除非提供类型,否则将拒绝该定义,因为推理无法为其选择一种最校正的类型。This is kind of the whole point of GADTs. Matching on a constructor can cause additional type information to come into scope.
Let's look at what happens when GHC checks the following definition:
Let's look at the
T2
case first, just to get it out of the way.y
and the result have the same type, andT2
is polymorphic, so you can declare its type is alsoT a
. All good.Then comes the trickier case. Note that I removed the binding of the name
x
inside thecase
as the shadowing might be confusing, the inner value isn't used, and it doesn't change anything in the explanation. When you match on a GADT constructor likeT1
, one that explicitly sets a type variable, it introduces additional constraints inside that branch which add that type information. In this case, matching onT1
introduces a(a ~ Bool)
constraint. This type equality says thata
andBool
match each other. Therefore the literalTrue
with typeBool
matches thea
written in the type signature.y
isn't used, so the branch is consistent withT a -> a -> a
.So it all matches up.
T a -> a -> a
is a valid type for that definition. But as Simon is saying, it's ambiguous.T a -> Bool -> Bool
is also a valid type for that definition. Neither one is more general than the other, so the definition doesn't have a principle type. So the definition is rejected unless a type is provided, because inference cannot pick a single most-correct type for it.类型
t a
带有a
与bool
不同的值永远不会具有表单t1 x
(因为那是仅类型t bool
)。因此,在这种情况下,
t1 x
case
中的分支变得无法访问,在类型检查/推理期间可以忽略。更具体地:GADT允许类型检查器在模式匹配过程中假设类型级方程,并在以后利用此类方程式。当检查
类型检查器执行以下推理时:
多亏了GADTS,案例的两个分支都具有
a
的类型,因此整个情况表达式具有类型a
和函数定义类型检查。更一般而言,当
X :: T A
和GADT构造函数定义为k :: ... ...-> T b
然后,当类型检查时,我们可以做出以下假设:请注意,
a
和b
可以是涉及类型变量的类型(如a〜中上面的bool
),因此允许获得有关它们的有用信息,并以后进行利用。A value of type
T a
witha
different fromBool
can never have the formT1 x
(since that has only typeT Bool
).Hence, in such case, the
T1 x
branch in thecase
becomes inaccessible and can be ignored during type checking/inference.More concretely: GADTs allow the type checker to assume type-level equations during pattern matching, and exploit such equations later on. When checking
the type checker performs the following reasoning:
Thanks to GADTs, both branches of the case have type
a
, hence the whole case expression has typea
and the function definition type checks.More generally, when
x :: T A
and the GADT constructor was defined asK :: ... -> T B
then, when type checking we can make the following assumption:Note that
A
andB
can be types involving type variables (as ina~Bool
above), so that allows one obtain useful information about them and exploit it later on.