Обратите внимание на следующий класс:
class ListIsomorphic l where
toList :: l a -> [a]
fromList :: [a] -> l a
Я также требую, чтобы toList . fromList == id
. Как написать правила перезаписи, чтобы сообщить GHC сделать эту замену?
Обратите внимание на следующий класс:
class ListIsomorphic l where
toList :: l a -> [a]
fromList :: [a] -> l a
Я также требую, чтобы toList . fromList == id
. Как написать правила перезаписи, чтобы сообщить GHC сделать эту замену?
Вы можете использовать RULES
прагму для реализации этого упрощения, но вам нужно сделать немного дополнительной работы, чтобы убедиться, что правила переписывания общих правил не огонь перед вашим имеет шанс:
{-# 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
Вот глупый пример, показывающий, что он работает:
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"
При этом Just "Hello"
выводится вместо ошибки. Кроме того, вы можете увидеть стрелки правил:
$ 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 ...