最近我实现了一个类似于Exception
的类型层次结构,其要点如下:
class (Typeable a) => Hierarchy a where
toHierarchy :: a -> HierarchyBase
fromHierarchy :: HierarchyBase -> Maybe a
-- HierarchyBase
data HierarchyBase = forall h. (Hierarchy h) => HierarchyBase h
instance Hierarchy HierarchyBase where
toHierarchy = id
fromHierarchy = Just
-- MyType ⊂ HierarchyBase
data MyType = forall e. (Hierarchy h) => MyType h
instance Hierarchy MyType where
toHierarchy x = HierarchyBase x
fromHierarchy (HierarchyBase x) = cast x
-- SubType ⊂ MyType ⊂ HierarchyBase
data SubType = SubType
instance Hierarchy SubType where
toHierarchy x = toHierarchy $ MyType x
fromHierarchy (HierarchyBase x) = cast x >>= \(MyType x') -> cast x'
-- dispatchHierarchy automatically casts a type into any of its ancestors.
-- for instance, you can do any of these:
-- > disptachHierarchy (f :: HierarchyBase -> ...) SubType
-- > disptachHierarchy (f :: MyType -> ...) SubType
-- > disptachHierarchy (f :: SubType -> ...) SubType
hierarchyDispatch :: (Hierarchy a, Hierarchy a') => (a' -> b) -> a -> b
hierarchyDispatch f h = f . fromJust . fromHierarchy . toHierarchy $ h
这个解决方案使用存在量化的数据构造函数来定义一些 subtypeable 层次类型。我尝试过不使用存在来重写它,但是我没有成功。
我知道,这样使用存在量词可以 * 隐藏 * 类型构造函数中使用的类型变量:数据类型并不依赖于它,我可以理解为什么定义Hierarchy
类型类及其示例需要这样做。
但是我不明白这个特性在什么时候或者为什么是有用的或者是必要的。现在,每当我在定义一个类型类或者示例的时候被一个类型的种类卡住的时候,我觉得我必须尝试使用存在量词。但是到目前为止它从来没有起作用。问题总是在别的地方。而且我的代码中充斥着不必要的存在量词(想想经典的例子,有[Showable 1, Showable 'a']
而不是简单的[show 1, show 'a']
)。
如何判断何时需要或使用存在量化数据构造函数,而不是不必要的开销?
1条答案
按热度按时间ltqd579y1#
存在数据类型到非存在数据类型的简化遵循参数性:在类型上进行模式匹配 in 能力。
但是
Typeable
比Show
难处理得多,这是可以理解的:Typeable a
本质上 * 意味着 *“您可以将类型a
与模式匹配”。即使您给予了Typeable
附带的“开放GADT”TypeRep a
并仅保留例如cast
操作符,您也会得到更高级别的类型:因此,涉及
Typeable
(包括你的)的存在类型 * 不能 * 被有意义地简化。如果确实无法控制量化类型的值的数量,存在类型也很有用,例如在
根据上面的方案简化此类型需要您在
f b
中“找到b
s”,并将b -> a
预应用于它们,但f
不是固定的,因此这是不可能的。(当f
是一个Functor
时,实际上是Coyoneda f a ~= f a
,但使用Coyoneda
仍有性能方面的原因。)唯一的出路是通用但无用的较高等级的转换:完成了这些示例后,我认为这是一个很好的地方,可以给出您问题的真实的答案:简化一个存在类型,甚至告诉它什么时候是可能的,都不是一件小事。对于不能简化的类型,有一些“明显”的标记,甚至可以简化的类型在简化之后看起来也会非常不同。最后一个类似的例子是,我最近想到了下面的类型。我用它来表示非平面表面上的导航:
这种类型很容易想到:我想到了需要处理的情况和操作,并将它们写了下来。然而,删除存在语句的方案实际上非常容易应用,并将
Map
简化为这种编码是更直观还是更不直观?在某些情况下,选择是否使用存在式更多地是关于你觉得什么容易思考,而不是必要性。