当前位置: 首页 > 知识库问答 >
问题:

这个涉及反射的神秘的Haskell类型错误的原因是什么?

秦钟展
2023-03-14

我在使用Haskell反射包时,遇到了一个我不完全理解的类型错误。首先,我尝试编写以下函数,它可以轻松地打字:

{-# LANGUAGE TypeApplications #-}

reifyGood :: (forall s. Reifies s a => Proxy a) -> ()
reifyGood p = reify undefined (\(_ :: Proxy t) -> p @t `seq` ())
reifyBad :: (forall s. Reifies s s => Proxy s) -> ()
reifyBad p = reify undefined (\(_ :: Proxy t) -> p @t `seq` ())
• Could not deduce (Reifies s s) arising from a use of ‘p’
  from the context: Reifies s a0
    bound by a type expected by the context:
               Reifies s a0 => Proxy s -> ()
• In the first argument of ‘seq’, namely ‘p @t’
  In the expression: p @t `seq` ()
  In the second argument of ‘reify’, namely
    ‘(\ (_ :: Proxy t) -> p @t `seq` ())’
reifyGood :: (forall s. Reifies s a => Proxy a) -> ()
reifyBad  :: (forall s. Reifies s s => Proxy s) -> ()

我觉得这很奇怪。乍一看,这是无效的,因为在第二个示例中,skolems将会逃避它的作用域。然而,这实际上不是真的--错误消息从未提到skolem escape,与这个略有不同的程序形成对比:

reifyBad' :: (forall s. Reifies s s => Proxy s) -> ()
reifyBad' p = reify undefined (\(_ :: Proxy t) -> p @t) `seq` ()
• Couldn't match expected type ‘t0’ with actual type ‘Proxy s’
    because type variable ‘s’ would escape its scope
  This (rigid, skolem) type variable is bound by
    a type expected by the context:
      Reifies s a0 => Proxy s -> t0
• In the expression: p @t
  In the second argument of ‘reify’, namely
    ‘(\ (_ :: Proxy t) -> p @t)’
  In the first argument of ‘seq’, namely
    ‘reify undefined (\ (_ :: Proxy t) -> p @t)’

所以也许还有别的东西在起作用。

检查Reify的类型,可以稍微清楚地看出有些问题:

reify :: forall a r. a -> (forall s. Reifies s a => Proxy s -> r) -> r
foo :: forall a r. Proxy a -> (forall s. (s ~ a) => Proxy s -> r) -> r
foo _ f = f Proxy

bar :: (forall a. Proxy a) -> ()
bar p = let p' = p in foo p' (\(_ :: Proxy s) -> (p' :: Proxy s) `seq` ())
• Couldn't match type ‘a0’ with ‘s’
    because type variable ‘s’ would escape its scope
  This (rigid, skolem) type variable is bound by
    a type expected by the context:
      Proxy s -> ()
  Expected type: Proxy s
    Actual type: Proxy a0
• In the first argument of ‘seq’, namely ‘(p' :: Proxy s)’
  In the expression: (p' :: Proxy s) `seq` ()
  In the second argument of ‘foo’, namely
    ‘(\ (_ :: Proxy s) -> (p' :: Proxy s) `seq` ())’

更具体地说,为什么会产生缺少实例的错误?

此外,这种行为是预期的、定义良好的,还是仅仅是typechecker的一个奇怪的边缘情况,碰巧产生了这种特定的结果?

共有1个答案

汲利
2023-03-14
reify :: forall a r. a -> (forall s. Reifies s a => Proxy s -> r) -> r

skolem需求本质上声明,上面类型中的R不能依赖于第二个参数中量化的S。否则,由于reify返回r,它实际上会“转义”其作用域。

reifyBad :: (forall s. Reifies s s => Proxy s) -> ()
reifyBad p = reify undefined (\(_ :: Proxy t) -> p @t `seq` ())

我们看到Reify的第二个参数是\(_::Proxy t)->p@t`seq`(),因此R类型将是该函数的返回类型,即()。由于R~()不依赖于S,所以这里没有逃避的问题。

相反,在变体中

reifyBad' :: (forall s. Reifies s s => Proxy s) -> ()
reifyBad' p = reify undefined (\(_ :: Proxy t) -> p @t) `seq` ()

这里R被推断为\(_::Proxy t)->p@t的返回类型,它是Proxy t,其中t~s。因为R~Proxy s确实依赖于s,所以我们触发一个skolem错误。

 类似资料:
  • 我对编程很陌生,我已经自学了将近一个月了,有谁能给我解释一下我代码中错误的原因吗?在“Total(moneyConv(moneySum*moneyRate))”中出错。行,表示实际和形式的论点在长度上是不同的。我检查了我所有的参数,我觉得很好。多谢!

  • minecraft 1.8.8的modcoderpack918中的有一个很大的问题。我的Java版本是1.8.0_271-B09。 我不知道我必须做什么。

  • 我是一个菜鸟,我在跟着 swift 官方文档进行学习。 ↓这是官方的示例图片,以证明我没有写错 示例代码如下,以便于大家复制 但是我在 Xcode 中却无法编译成功(最后 struct... 不是我自己改的,文件创建出来就是这样的,好像是写法改了)

  • 下面我写了一个C++函数,它通过一个整数向量进行循环。每通过一次,它就从所有的数字中减去最小的数字。它应该在每次传递时返回非零元素的数量(这存储在向量结果中并返回)。然而,每当我尝试运行时,我都会得到“std::bad_alloc”。当删除行“flag=true”时,错误就会消失。我将需要它工作,以便while循环中断。帮我修好这个。

  • 问题内容: 嗯,我已经找了很多地方在互联网上的原因,其称 无法更新存储函数/触发器中的表“ unlucky_table”,因为调用该存储函数/触发器的语句已使用该表 有人说这是mysql中的错误或它没有提供的功能。 MySQL触发器无法操纵分配给它们的表。所有其他主要的DBMS都支持此功能,因此希望MySQL会尽快添加此支持。 有人声称这是由于当您插入一条记录时递归行为 mysql正在做一些锁定操

  • 我有一个wordpress博客。当我登录到仪表板时,以下异常在顶部突出显示: 从异常消息中,我可以推断它与谷歌分析及其API有关 然而,我很想知道是什么导致了这个异常。此外,我可以采取哪些措施来避免此类例外情况?