【发布时间】:2015-05-06 19:12:33
【问题描述】:
我正在尝试编写一个函数(此处称为hide),它可以在存在包装器内应用足够多态的函数(或提升函数以在具有隐藏类型的包装器上工作;因此“隐藏”):
{-# LANGUAGE GADTs
, RankNTypes
#-}
data Some f
where Some :: f a -> Some f
hide :: (forall a. f a -> g b) -> Some f -> Some g
hide f (Some x) = Some (f x)
data Phantom a = Phantom
cast :: Phantom a -> Phantom b
cast Phantom = Phantom
works :: Some Phantom -> Some Phantom
works = hide cast
doesn't :: Functor f => Some f -> Some f
doesn't = hide (fmap $ \x -> [x])
{-
foo.hs:23:17:
Couldn't match type ‘b0’ with ‘[a]’
because type variable ‘a’ would escape its scope
This (rigid, skolem) type variable is bound by
a type expected by the context: f a -> f b0
at foo.hs:23:11-33
Expected type: f a -> f b0
Actual type: f a -> f [a]
In the first argument of ‘hide’, namely ‘(fmap $ \ x -> [x])’
In the expression: hide (fmap $ \ x -> [x])
In an equation for ‘doesn't’: doesn't = hide (fmap $ \ x -> [x])
Failed, modules loaded: none.
-}
but :: Functor f => Some f -> Some f
but = hide' (fmap $ \x -> [x])
where hide' :: (forall a. f a -> g [a]) -> Some f -> Some g
hide' f (Some x) = Some (f x)
所以我非常理解为什么会这样; works 表明当返回类型与输入类型完全无关时,hide 确实有效,但在doesn't 中,我使用a -> [a] 类型的参数调用hide。 hide 应该可以“选择”a (RankNTypes) 类型,但 b 通常是多态的。当b 实际上依赖于a 时,a 可能会泄露出去。
但在我实际调用它的上下文中,a 实际上并没有泄漏;我立即用Some 把它包起来。事实上,我可以编写一个替代的hide',它专门接受a -> [a] 函数并且使用完全相同的实现,只是不同的类型签名。
有什么方法可以输入实现hide f (Some x) = Some (f x) 以便它更普遍地工作?我真的对a -> q a 类型的提升函数很感兴趣,其中q 是一些任意类型的函数;即我希望返回类型取决于a,但我不在乎它是如何做到的。可能有q a 是常量的用例(即返回类型不依赖于a),但我想它们会少得多。
显然,这个例子很愚蠢。在我的实际用例中,我有一个 GADT Schema a,粗略地说它代表外部类型系统中的类型; phantom 参数给出了一个 Haskell 类型,可以用来表示外部类型系统中的值。我需要那个幻像参数来保证所有类型的安全,但有时我会根据运行时数据构造Schemas,在这种情况下我不知道那个参数类型是什么。
所以我似乎需要另一种与类型参数无关的类型。我希望使用像Some 这样的简单存在包装器从Schema 构造它,并能够将forall a. Schema a -> Schema b 类型的函数提升到Some Schema -> Some Schema,而不是制造(还)另一种并行类型。因此,如果我有一个 XY 问题,并且我最好使用一些其他方式将 Schema a 传递给未知的 a,这也可以解决我的问题。
【问题讨论】:
-
如果您将其键入为
hide :: (forall a. f a -> g (q a)) -> Some f -> Some g,doesn't类型检查,但这可能不像您正在寻找的那样普遍(当q ~ Id时您不能使用它,其中@987654357 @ 例如)。 -
@DavidYoung 我会试试看,看看效果如何;我不喜欢它作为向我的图书馆用户公开的组合器,但它很可能满足我的大部分内部需求(因为在
a中具有足够的多态性,我通常只是将它包装成其他多态的东西)。 -
另外,我不确定这是否对解决这个问题有很大帮助,但是这件事让我想起了很多我开始开发的用于处理存在主义的包(主要是不过现在专注于存在主义列表):github.com/roboguy13/anylist。底部注释掉的东西可能最有可能适用于此(特别是,我在想多类
Functor类的Existential实例),但它可能还没有功能(但我不完全记得)。