Haskell 中存在类型的类型错误
我在程序中与存在类型作斗争。我认为我正在尝试做一些非常合理的事情,但是我无法通过类型检查器:(
我有一个有点模仿 Monad 的数据类型
data M o = R o | forall o1. B (o1 -> M o) (M o1)
现在我为它创建一个上下文,类似于 关于 Zipper 的 Haskell Wiki 文章,但是为了简单起见,我使用函数而不是数据结构 -
type C o1 o2 = M o1 -> M o2
现在,当我尝试编写一个将数据值拆分为的函数时它的背景和subvalue,类型检查器抱怨 -
ctx :: M o -> (M o1 -> M o, M o1)
ctx (B f m) = (B f, m) -- Doesn't typecheck
错误是 -
Couldn't match type `o2' with `o1'
`o2' is a rigid type variable bound by
a pattern with constructor
B :: forall o o1. (o1 -> M o) -> M o1 -> M o,
in an equation for `ctx'
at delme1.hs:6:6
`o1' is a rigid type variable bound by
the type signature for ctx :: M o -> (M o1 -> M o, M o1)
at delme1.hs:6:1
Expected type: M o2
Actual type: M o1
In the expression: m
In the expression: (B f, m)
但是,我可以像这样解决它 -
ctx (B f m) = let (c,m') = ctx m in ((B f) . c, m') -- OK
为什么第二个定义进行类型检查而不是第一个定义?
另外,如果我尝试将 ctx 转换为完整的函数?通过检查 R,我再次收到类型检查错误 -
ctx (R o) = (id, R o) -- Doesn't typecheck
-
Couldn't match type `o' with `o1'
`o' is a rigid type variable bound by
the type signature for ctx :: M o -> (M o1 -> M o, M o1)
at delme1.hs:7:1
`o1' is a rigid type variable bound by
the type signature for ctx :: M o -> (M o1 -> M o, M o1)
at delme1.hs:7:1
In the first argument of `R', namely `o'
In the expression: R o
In the expression: (id, R o)
我该如何解决此错误?
错误
I am struggling with existential types in my program. I think I'm trying to do something very reasonable however I cannot get past the typechecker :(
I have a datatype that sort of mimics a Monad
data M o = R o | forall o1. B (o1 -> M o) (M o1)
Now I create a Context for it, similar to that described in Haskell Wiki article on Zipper, however I use a function instead of a data structure for simplicity -
type C o1 o2 = M o1 -> M o2
Now when I try to write a function that splits a data value into its context and subvalue, the typechecker complains -
ctx :: M o -> (M o1 -> M o, M o1)
ctx (B f m) = (B f, m) -- Doesn't typecheck
Error is -
Couldn't match type `o2' with `o1'
`o2' is a rigid type variable bound by
a pattern with constructor
B :: forall o o1. (o1 -> M o) -> M o1 -> M o,
in an equation for `ctx'
at delme1.hs:6:6
`o1' is a rigid type variable bound by
the type signature for ctx :: M o -> (M o1 -> M o, M o1)
at delme1.hs:6:1
Expected type: M o2
Actual type: M o1
In the expression: m
In the expression: (B f, m)
However, I can work around it like so -
ctx (B f m) = let (c,m') = ctx m in ((B f) . c, m') -- OK
Why does this second definition typecheck but not the first one?
Also, if I try to convert ctx
to a complete function by checking for R, I again get a typecheck error -
ctx (R o) = (id, R o) -- Doesn't typecheck
Error -
Couldn't match type `o' with `o1'
`o' is a rigid type variable bound by
the type signature for ctx :: M o -> (M o1 -> M o, M o1)
at delme1.hs:7:1
`o1' is a rigid type variable bound by
the type signature for ctx :: M o -> (M o1 -> M o, M o1)
at delme1.hs:7:1
In the first argument of `R', namely `o'
In the expression: R o
In the expression: (id, R o)
How can I work around this error?
Any help is appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我们先来看看失败的案例。这两个失败的原因相同,一旦您在类型签名中添加隐式
forall
,这一点就更清楚了:即您的函数必须不仅适用于某个
o1
,但对于任何o1
。在第一种情况下,
我们知道
f :: (o2 -> M o)
和m :: M o2
,对于 some 类型o2
,但我们必须能够提供任何类型o1
,所以我们不能假设o1 ~ o2
.在第二种情况下,
在这里,我们知道
o :: o
,但同样,必须为 anyo1
定义该函数,因此我们可以不要假设o ~ o1
。您的解决方法似乎只起作用,因为它在调用自身,类似于归纳证明。但是如果没有基本情况,这只是循环推理,并且您无法为该函数编写基本情况,因为无法从
M o
构造M o1
对于o
和o1
的任意组合,而不使用底部值。您可能需要做的是为上下文定义另一个存在类型,而不是仅使用元组。不确定它是否能满足您的需求,但这至少可以编译1:
1尝试使用
let
而不是一个有趣的 GHC 错误的案例
:)Let's look at the failing cases first. Both of these fail for the same reason, which is clearer once you add in the implicit
forall
in the type signature:i.e. your function must not only work for a some
o1
, but for anyo1
.In your first case,
we know that
f :: (o2 -> M o)
andm :: M o2
, for some typeo2
, but we have to be able to offer any typeo1
, so we can't assume thato1 ~ o2
.In the second case,
Here, we know that
o :: o
, but again, the function has to be defined for anyo1
, so we can't assume thato ~ o1
.Your workaround only seems to work because it's calling itself, similar to an inductive proof. But without a base case, it's just circular reasoning, and you cannot write the base case for this function, because there is no way to construct an
M o1
from anM o
for any combination ofo
ando1
without using a bottom value.What you'll probably need to do, is to define another existential type for the context, instead of using just a tuple. Not sure if it'll work for your needs, but this compiles1, at least:
1 Try using a
let
instead ofcase
for a funny GHC error :)