Haskell 如何为typeclass方法编写重写规则?

Haskell 如何为typeclass方法编写重写规则?,haskell,optimization,ghc,Haskell,Optimization,Ghc,注意以下几点: class ListIsomorphic l where toList :: l a -> [a] fromList :: [a] -> l a 我还要求toList。fromList==id。我如何编写重写规则来告诉GHC进行替换?您可以使用规则杂注来实现此简化,但您必须确保在您有机会执行以下操作之前不会触发通用方法重写规则: {-# RULES "protect toList" toList = toList'; "prote

注意以下几点:

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

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

您可以使用
规则
杂注来实现此简化,但您必须确保在您有机会执行以下操作之前不会触发通用方法重写规则:

{-# 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"
这只打印“你好”
,而不是出错。此外,您还可以看到规则:

$ 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 ...

这其实并不“明显”。这是你必须明确要求的财产。例如,你可以有一个树结构,你可以将它转换成一个列表,你也可以从一个列表中构造它,但是这个标识不一定成立,这听起来很合理。谢谢。另外,
l
toList
fromList
调用之间不能有区别吗?例如
redBlackTreeToBTree=toList。fromList
where
redBlackTreeToBTree::RedBlackTree a->BTree a
。是的,它可以。考虑到这一点,我想唯一正确的答案是在每个实例中编写一个特定的规则。这可能吗?@NathanDavis我想是
toList。fromList::ListIsomorphic l=>[a]->[a]
(它有一个模棱两可的“中间实例”,但只有一个),因此我认为不可能涉及两个不同的实例。