当我在构造函数中使用符号创建新类型时,打开了 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"
有没有办法在运行时提供字符串符号值? 如果不允许这样做,为什么它甚至会编译(即 - 如果它没有解析为默认情况之外的任何内容,那么什么时候有人甚至想在第三次打印中使用作业?
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
;那么很明显,let
没有帮助,你不妨写undefined :: forall name. Object name
。由于有许多实例与此类型匹配,并且您告诉GHC您不在乎在这种情况下选择哪个实例,因此它继续选择一个实例。这不是你想要的,但这是你为不连贯的实例付出的代价。