How do you write rewrite rules for typeclass methods?

后端 未结 1 884

Mind the following class:

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

I also demand that

相关标签:
1条回答
  • 2020-12-30 07:22

    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 ...
    
    0 讨论(0)
提交回复
热议问题