How do you write rewrite rules for typeclass methods?

半世苍凉 提交于 2019-11-29 07:31:32

问题


Mind the following class:

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

I also demand that toList . fromList == id. How do I write rewrite rules to tell GHC to make that substitution?


回答1:


You can use a RULES pragma to implement this simplification but you have to do a bit of extra work to make sure the generic method rewrite rules don't fire before yours have a chance to:

{-# 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

Here's a silly example to show that it works:

instance ListIsomorphic Maybe where
    toList = error "toList"
    fromList = error "fromList"

test1 :: Maybe a -> Maybe a
test1 x = fromList (toList x)

main = print $ test1 $ Just "Hello"

This prints Just "Hello" instead of erroring out. Also, you can see the rules firing:

$ ghc -O -ddump-rule-firings --make rewrite-method.hs
[1 of 1] Compiling Main             ( rewrite-method.hs, rewrite-method.o )
Rule fired: protect toList
Rule fired: protect fromList
Rule fired: unpack
Rule fired: unpack
Rule fired: protect toList
Rule fired: protect fromList
Rule fired: fromList/toList
Rule fired: unpack
Rule fired: Class op show
Rule fired: >#
Rule fired: tagToEnum#
Rule fired: Class op showsPrec
Rule fired: Class op showList
Rule fired: ++
Rule fired: unpack-list
Rule fired: foldr/app
Rule fired: unpack-list
Rule fired: unpack-list
Linking rewrite-method.exe ...


来源:https://stackoverflow.com/questions/32130011/how-do-you-write-rewrite-rules-for-typeclass-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!