GHC重写规则专门为一个类型类的函数
使用GHC RULES
编译指示,可以为特定类型专门设计一个多态函数。 来自Haskell报告的例子:
genericLookup :: Ord a => Table a b -> a -> b
intLookup :: Table Int b -> Int -> b
{-# RULES "genericLookup/Int" genericLookup = intLookup #-}
这将使GHC在整数索引表上使用intLookup
,否则在泛型上使用intLookup
,其中intLookup
可能更有效。
我想用类似下面的(稍微简化的)函数来完成类似的事情:
lookup :: Eq a => [(a, b)] -> a -> b
lookupOrd :: Ord a => [(a, b)] -> a -> b
其中lookupOrd
创建Map
从输入列表,然后使用Map.lookup
,这就要求a
是成员Ord
。
现在我想告诉GHC,只要a
确实是Ord
类型的成员, lookupOrd
应该使用lookupOrd
而不是lookup
。 但是,以下规则不会检查:
{-# RULES "lookup/Ord" lookup = lookupOrd #-}
GHC(理所当然地)抱怨说它不能从上下文(Eq a)
推出(Ord a)
(Eq a)
。 是否有一个重写规则可以让我执行这种基于类的专业化?
我认为不存在,并且有一个原因,为什么GHC目前的实施难以实现:
虽然您在Haskell语法中指定规则,但它们将应用于GHC的Core语言。 在那里,类型的类约束已经变成了字典参数,所以函数
lookup :: Eq a => a -> [(a,b)] -> Maybe b
现在已经打字
lookup :: forall a b. Eq a -> a -> [(a, b)] -> Maybe b
而你的lookupOrd
会有类型
lookupOrd :: forall a b. Ord a -> a -> [(a, b)] -> Maybe b
其中, Eq a
和Ord a
已经成为普通的数据类型。 特别是在这个阶段,不再有类型的类型的概念; 所有已经解决的问题。
所以现在假设编译器发现了一个
lookup (dict :: Eq MyType) (x :: MyType) (list :: [(MyType, String)])
它应该取代什么? 你告诉他, x
和list
也可以传递给lookupOrd
,但是该函数也需要Ord MyType
类型的值,该值不会出现在规则的左侧。 所以GHC必须放弃。
像一条规则
{-# RULES "lookup/Ord" forall a x. lookup a x = lookupOrd (a::()) x #-}
尽管如此,这里有问题的参数( Ord
字典)已经在规则中修复,并且在应用规则时不需要找到。
原则上,其他编译器设计可能允许您想要的表单规则。
虽然这是一个古老的问题,但未来的Google人可能有兴趣知道有一种方法可以使用ifcxt软件包来执行OP所需的操作。
您可以查看更多示例的文档,但基本上可以使用第二个示例,示例2:使代码渐近有效,作为基础。
有了这两个功能,
lookup :: Eq a => [(a, b)] -> a -> b
lookupOrd :: Ord a => [(a, b)] -> a -> b
你会做,
cxtLookup :: forall a. (Eq a, IfCxt (Ord a)) => [(a, b)] -> a -> b
cxtLookup = ifCxt (Proxy::Proxy (Ord a)) lookupOrd lookup
这将允许您根据数据结构实现的类型特性选择最有效的函数。
请注意,我不知道它会对性能产生多大影响,但我认为与查找函数的运行时间相比,它是微不足道的,因此确实值得。
链接地址: http://www.djcxy.com/p/43065.html上一篇: GHC rewrite rule specialising a function for a type class