【问题标题】:Type errors with Existential types in HaskellHaskell 中存在类型的类型错误
【发布时间】:2012-01-06 15:19:24
【问题描述】:

我在我的程序中与存在类型作斗争。我想我正在尝试做一些非常合理的事情,但是我无法通过类型检查器:(

我有一个类似于 Monad 的数据类型

data M o = R o | forall o1. B (o1 -> M o) (M o1)

现在我为它创建一个上下文,类似于Haskell Wiki article on Zipper 中描述的内容,但是为了简单起见,我使用函数而不是数据结构 -

type C o1 o2 = M o1 -> M o2

现在,当我尝试编写一个将数据值拆分为其上下文和子值的函数时,类型检查器会抱怨 -

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

为什么第二个定义类型检查而不是第一个?

另外,如果我尝试通过检查 R 将 ctx 转换为完整的函数,我再次收到类型检查错误 -

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)

如何解决此错误?

感谢任何帮助!

【问题讨论】:

    标签: haskell typeerror typechecking existential-type zipper


    【解决方案1】:

    让我们先看看失败的案例。由于相同的原因,这两个都失败了,一旦您在类型签名中添加隐式forall,就会更清楚:

    ctx :: forall o o1. M o -> (M o1 -> M o, M o1)
    

    即您的函数不仅适用于某些 o1,而且适用于 any o1

    1. 在您的第一种情况下,

      ctx (B f m) = (B f, m)
      

      我们知道f :: (o2 -> M o)m :: M o2,对于一些 类型o2,但我们必须能够提供任何 类型o1,所以我们不能假设o1 ~ o2

    2. 第二种情况,

      ctx (R o) = (id, R o)
      

      在这里,我们知道o :: o,但同样,必须为any o1 定义函数,所以我们不能假设o ~ o1

    您的解决方法似乎只起作用,因为它正在调用自己,类似于归纳证明。但是没有基本情况,它只是循环推理,你不能为这个函数编写基本情况,因为没有办法从M ooo1 的任何组合构造一个M o1使用底部值。

    您可能需要做的是为上下文定义另一个存在类型,而不是只使用一个元组。不确定它是否能满足您的需求,但这至少可以编译1

    data Ctx o = forall o1. Ctx (M o1 -> M o) (M o1)
    
    ctx :: M o -> Ctx o
    ctx (B f m) = case ctx m of Ctx c m' -> Ctx (B f . c) m'
    ctx (R o)   = Ctx id (R o) 
    

    1 尝试使用let 而不是case 代替a funny GHC error :)

    【讨论】:

    • 谢谢!使用存在类型而不是元组效果很好,在这个过程中我学到了很多东西!
    猜你喜欢
    • 2011-02-08
    • 1970-01-01
    • 2013-09-04
    • 2013-12-18
    • 1970-01-01
    • 2011-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多