来自Haskell文件:
import GHC.Exts (Constraint)
-- |Existential wrapper
data Some :: (* -> Constraint) -> * where
Some :: f a => { unSome :: a } -> Some f
我知道Constraint
表示与*
不同的一种,可用于对=>
左侧显示的上下文类型进行分类。
但在什么意义上Some
是一个存在主义的包装?怎么可以这样使用呢?
答案 0 :(得分:3)
奇怪的GADT /记录语法看起来不应该被编译出去,我们可以通过设置f ~ Eq
来了解这里发生了什么:
Some :: Eq a => a -> Some Eq
所以,给定一个Eq
可用的东西,我们得到Some Eq
可用的东西。我们将此应用于'a' :: Char
,看看会发生什么:
(Some :: Eq Char => Char -> Some Eq) ('a' :: Char) :: Some Eq
正如你所看到的,我们已经忘记了#34;这个值的确切类型,但是记得"它是Eq
可以使用的。
您提供的GADT只是从Eq
到类似* -> Constraint
的任何内容的概括:
(Eq :: * -> Constraint) (Char :: *) :: Constraint
(f :: * -> Constraint) (a :: *) :: Constraint
为什么它被称为"存在",GADT在构造函数声明中隐藏了一个隐含的forall
:
Some :: forall a. f a => { unSome :: a } -> Some f
在Some f
上进行模式匹配后,您会获得f a => a
类型的值,其中a
由于技术原因无法逃避其范围。 (这称为skolem)您可以使用这样的CPS组合器来处理它:
ambiguously :: (forall s. f s => s -> r) -> Some f -> r
ambiguously f (Some s) = f s
现在你有ambiguously show :: Some Show -> String
,它显示了Some Show
能够做到的事情。它被称为"含糊不清"因为它使用的实际类型不明确(即它适用于ambiguously show $ Some 'a'
和ambiguously show $ Some "asdf"
)
我们无法做到
disambiguate :: f a => Some f -> a
disambiguate (Some a) = a
因为上述限制。
My (unpublished) library与此相关,更为一般。