IncoherentInstances选择错误的实例

时间:2013-11-13 18:22:56

标签: haskell

当我在构造函数中创建一个带有符号的新类型时,如果启用了IncoherentInstances,则只有在编译时填充符号时才会选择该类型的正确实例....

{-# LANGUAGE DataKinds, GADTs, KindSignatures, FlexibleInstances, IncoherentInstances #-}

import GHC.TypeLits

data Object:: Symbol -> * where
    Object :: Object sy

instance Show (Object "dog") where
    show _ = "dog"

instance Show (Object x) where
    show _ = "other"

main = do
    let name = "dog"
    print (undefined :: Object "dog") -- outputs "dog", as expected
    print (undefined :: Object "cat") -- outputs "other", as expected
    print (undefined :: Object name) -- outputs "other", I expected "dog"

有没有办法在运行时提供字符串符号值?如果不允许这样做,为什么它甚至可以编译(即,如果除了默认情况下没有解决任何问题,有人甚至想在第三次打印中使用该赋值?)

1 个答案:

答案 0 :(得分:4)

Haskell [GHC]有两个完全独立的名称空间:术语和类型[和种类]。这就是你一直看到这种事情的原因:

data Foo a = Foo a | Bar Int

声明(除其他外)两个单独的名称Foo;一个是类型级名称Foo,它是一个类型构造函数,另一个是术语级名称Foo,它是一个数据构造函数。同样,在

foo :: a -> a
foo a = a

两个单独的名称a:一个是类型级别名称a,它是一个类型变量,另一个是术语级别名称{{1这是一个术语变量。

两个级别之间的交互是键入判断:一个级别的名称可能在上面的级别中具有已知的分类。例如,术语级别的名称a按类型级别的Just类型进行分类;然而,即使在这里,名称也不会互动。如果要连接术语级别名称和类型级别名称,则必须执行一些very exotic trickery

因此,当您撰写a -> Maybe a时,您应该将其视为let name = "dog" in undefined :: Object name之类的内容;很明显,let TermLevel.name = "dog" in undefined :: Object TypeLevel.name没有帮助,你也可以只写let。由于有很多实例符合这种类型,并且你告诉GHC你并不关心它在这种情况下选择了哪个实例,所以它继续选择了一个。它不是你想要的那个,但这是用不连贯的实例支付的价格。