我有一个名为Showable的类型:
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE ExplicitForAll #-}
data Showable = forall a . Show a => Showable a
然后制作一个包装它的功能是微不足道的。我只需写:
pack :: forall a . Show a => a -> Showable
pack x = Showable x
然而,似乎不可能创建将从Showable中解压缩数据的反函数。如果我试图反驳我为包写的内容并写下来:
unpack :: exists a . Show a => Showable -> a
unpack (Showable x) = x
然后我从GHC收到错误。
我查看了有关GHC语言扩展的文档,似乎不支持exists关键字。我已经看到它可能在其他一些Haskell编译器中,但我更愿意能够在GHC中完成它。
有趣的是,我仍然可以在Showable上进行模式匹配,并以这种方式从内部提取数据。所以我可以通过这种方式获得它的价值,但如果我想创建一个涉及Showable的无点函数,那么我需要解压缩。
那么有没有办法在GHC的Haskell中实现解包,可能使用类型系列或其他一些GHC扩展的神秘魔法?
答案 0 :(得分:4)
您键入的unpack
无法写入。原因是存在变量a
“逃避”模式匹配的范围,并且没有跟踪该行为的工具。引用文档:
data Baz = forall a. Eq a => Baz1 a a | forall b. Show b => Baz2 b (b -> b)
当模式匹配时,每个模式匹配为每个存在类型变量引入一个新的,不同的类型。这些类型不能与任何其他类型统一,也不能脱离模式匹配的范围。例如,这些片段不正确:
f1 (MkFoo a f) = a
结果类型中的这个“a”是什么?显然我们不是这个意思:
f1 :: forall a. Foo -> a -- Wrong!
原始程序是完全错误的。这是另一种错误
f2 (Baz1 a b) (Baz1 p q) = a==q
可以说
a==b
或p==q
,但a==q
是错误的,因为它等同于两个Baz1
构造函数产生的两种不同类型。
但是,您可以等效地重写unpack
类型,以便存在主体不转义:
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-}
module Lib where
data Showable = forall a. Show a => Showable a
pack :: Show a => a -> Showable
pack = Showable
unpack :: Showable -> (forall a. Show a => a -> r) -> r
unpack (Showable a) a2r = a2r a