I don’t think there is, and there is a reason why it is not easily possible with GHC’s current implementation:
Although you specify rules in Haskell syntax, they are going to be applied to GHC’s Core language. There, type class constraints have been turned into dictionary arguments, so the function
lookup :: Eq a => a -> [(a,b)] -> Maybe b
has now type
lookup :: forall a b. Eq a -> a -> [(a, b)] -> Maybe b
while your lookupOrd
would have type
lookupOrd :: forall a b. Ord a -> a -> [(a, b)] -> Maybe b
where Eq a
and Ord a
have become ordinary data types. In particular, at this stage, there is no notion of the type class for a type any more; all that has been resolved earlier.
So now assume the compiler finds an occurrence of
lookup (dict :: Eq MyType) (x :: MyType) (list :: [(MyType, String)])
What should it replace it with? You told him that x
and list
can be passed to lookupOrd
as well, but that function also wants a value of type Ord MyType
, which does not occur on the left-hand side of the rule. So GHC has to give up.
A rule like
{-# RULES "lookup/Ord" forall a x. lookup a x = lookupOrd (a::()) x #-}
works, though, as here the problematic argument (the Ord
dictionary) is already fixed in the rule, and does not need to be found when applying the rule.
In principal, other compiler designs might allow rules of the form that you want.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…