提升的数据类型具有固定数量的类型,这些类型是提升数据类型的成员。在这个封闭的世界中,支持在没有字典的字典中调用类型类的函数是否有意义?
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
data DataType = Constructor
data DataTypeProxy (e :: DataType) = DataTypeProxy
class Class (e :: DataType) where
classFunction :: DataTypeProxy e -> IO ()
-- this is the only instance that can be created
instance Class 'Constructor where
classFunction _ = return ()
-- adding the Class constraint fixes the build break
-- disp :: Class e => DataTypeProxy e -> IO ()
disp :: DataTypeProxy e -> IO ()
disp = classFunction
main :: IO ()
main = disp (DataTypeProxy :: DataTypeProxy 'Constructor)
这个人为的例子在GHC负责人中不起作用。这并不奇怪,但似乎DataKind
扩展可能使这成为可能。
test.hs:18:8:
No instance for (Class e) arising from a use of `classFunction'
Possible fix:
add (Class e) to the context of
the type signature for disp :: DataTypeProxy e -> IO ()
In the expression: classFunction
In an equation for `disp': disp = classFunction
答案 0 :(得分:4)
没有。允许这样做意味着幻像数据类型需要在运行时用额外的类型信息“标记”,并且会产生歧义。
data DataType = Constructor | SomethingElse
data DataTypeProxy (e :: DataType) = DataTypeProxy
...
instance Class 'SomethingElse where
classFunction _ = putStrLn "hello world"
instance Class 'Constructor where
classFunction _ = return ()
disp :: DataTypeProxy e -> IO ()
disp = classFunction
main = disp DataTypeProxy
这个程序应该做什么?它应该编译吗?如果没有,那么通过将构造函数添加到类型中,我们获取了一个您想要编译的程序,并生成了一个不需要的程序。如果它不应该编译,那么它有两个有效的行为。
main = disp (DataTypeProxy :: DataTypeProxy 'Constructor)
只有一种可能的解释......但它要求你以幻影类型发送。也就是说,
main = disp (DataTypeProxy :: DataTypeProxy 'SomethingElse)
是术语级别的相同程序,但具有不同的行为。这基本上打破了所有漂亮的属性,如参数化。基于类的基于类的调度是对此的解决方案,因为范围中的哪些实例以可预测(并且语义指定)的方式影响程序行为。