3

当我在构造函数中创建一个带有 Symbol 的新类型并打开 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"

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

4

1 回答 1

4

Haskell [GHC] 有两个 [三个] 完全独立的命名空间:术语和类型 [和种类]。这就是为什么你总是看到这种事情:

data Foo a = Foo a | Bar Int

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

foo :: a -> a
foo a = a

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

两个级别之间唯一的交互是输入判断:一个级别的名称可能在上面的级别中有一个已知的分类。例如,Just术语级别的名称在a -> Maybe a类型级别按类型分类;但是,即使在这里,名称也不会相互作用。如果你想连接一个术语级别的名称和一个类型级别的名称,你必须做一些非常奇特的诡计

所以当你写的时候let name = "dog" in undefined :: Object name,你应该把它读成这样let TermLevel.name = "dog" in undefined :: Object TypeLevel.name;那么很明显 thelet没有帮助,您不妨只写undefined :: forall name. Object name. 由于有很多实例与这种类型匹配,并且您告诉 GHC 在这种情况下您不在乎它选择哪个实例,所以它继续选择了一个。这不是您想要的,但这是您为不连贯的实例付出的代价。

于 2013-11-13T19:23:10.817 回答