解析存在类型中的函数调用

时间:2014-12-13 07:43:41

标签: haskell types existential-type

在阅读Haskell中存在的this page后,我被迫测试了这种行为的限制,所以我编写了以下代码片段:

{-# LANGUAGE ExistentialQuantification #-}

data Showable = forall a. Show a => MkShowable a

pack :: Show a => a -> Showable
pack = MkShowable

instance Show Showable where
    show (MkShowable x) = show x

Showable类型与上述链接中创建的ShowBox类型非常相似。然后我创建了这个人为的例子来说明我的问题。

showSomething :: Bool -> Showable
showSomething True = pack 1
showSomething False = pack "ABC"

main :: IO ()
main = do
  x <- getLine
  let y = read x
  print $ showSomething y

此代码(工作正常)要求用户输入(应为“True”或“False”),然后打印出1(如果为True)或"ABC"(如果是)假

但我没能完全理解系统是如何做到这一点的。从数学上讲,它非常有意义。但我不知道计算机是如何解决它的。对我来说,系统似乎在运行时决定是否调用Int的{​​{1}}实例或show的{​​{1}}函数,但这意味着存在类似C ++的vtable,我不相信Haskell有一个概念。

我的问题是:它如何解决这个问题?系统无法事先知道我是要输入true还是false,因此它无法知道在编译时调用哪个String,但它在两种情况下都清楚有效。

2 个答案:

答案 0 :(得分:6)

如何实现类型类的一种方法是传递一个实现类型类的函数字典。例如带签名的函数

f :: Show a => T

将被翻译成

f' :: (a -> String) -> T

由编译器在show内使用f时,它被附加参数替换(实际上会有更多函数,所有这些都在{{1}中声明})。

类似于数据类型

Show

将被翻译成

forall a . Show a => MkShowable a

因此转换后的代码可能如下所示:

forall a . MkShowable' (a -> String) a

调用{-# LANGUAGE ExistentialQuantification #-} data Showable' = forall a . MkShowable' (a -> String) a pack' :: Show a => a -> Showable' pack' = MkShowable' show instance Show Showable' where show (MkShowable' f x) = f x showSomething :: Bool -> Showable' showSomething True = pack' 1 showSomething False = pack' "ABC" 时,pack实现也会传递给构造函数,以便在需要时可用。

答案 1 :(得分:2)

是的。 Haskell中的一堆语言特性(大多数是扩展)可以被视为基本上实现了许多概念,这些概念捆绑在&#34;类&#34;的复杂整体中。在OO编程中,但单独作为单独的功能。基本上的类型类约束的存在类型是 vtables!

为了使show (MkShowable x)能够在没有任何其他限制的情况下工作,MkShowable x必须包含足够的信息以了解如何show x。这就是它的作用;即使它只有一个字段,它实际上也包含其他信息。

这与函数foo :: Show a => a; foo x = show x似乎只有一个参数的方式基本相同,但实际上必须获得足够的附加信息以了解show x;它不能“硬连线”#34; in因为foo可能用于几种不同的类型。但是foo要求其调用者从外部传递该信息(并且类型系统强制执行此操作),Showable包含完全相同的信息,以便能够提取它以传递给foo等函数。

所以现在使用这个工具,与没有ExistentialQuantification不同的是,知道要调用哪个show实例的问题只是在两个相同类型的值之间进行选择(其中包含一个Show实例一些未知的类型以及相同类型的值),这很容易做到;没有编译时知道它是哪一个。