在重载函数上使用重写规则

在这个问题中 ,@ Virlib 询问使用重写规则来利用类型规则来消除一些重载函数调用:

请注意以下类:

class ListIsomorphic l where
    toList    :: l a -> [a]
    fromList  :: [a] -> l a

我也要求 toList . fromList == id。如何编写重写规则来告诉 GHC 进行替换?

对于 GHC 的重写规则机制来说,这是一个有点棘手的用例,因为重载的函数被 GHC 在幕后隐式创建的规则重写为它们的特定实例方法 (所以像 fromList::Seq a -> [a] 这样的东西会被重写为 Seq$fromList 等)。

但是,通过首先将 toListfromList 重写为非内联非类型类方法,我们可以保护它们免于过早重写 ,并保留它们直到组合规则可以触发:

{-# RULES
  "protect toList"   toList = toList';
  "protect fromList" fromList = fromList';
  "fromList/toList"  forall x . fromList' (toList' x) = x; #-}

{-# NOINLINE [0] fromList' #-}
fromList' :: (ListIsomorphic l) => [a] -> l a
fromList' = fromList

{-# NOINLINE [0] toList' #-}
toList' :: (ListIsomorphic l) => l a -> [a]
toList' = toList