GHC REWRITE pragma必须保持类型吗?

wen*_*wen 5 haskell pragma ghc

import Data.Void (Void,absurd)
Run Code Online (Sandbox Code Playgroud)

说我有一个小语言:

data Term c v where
  Var :: v               -> Term c v
  Con :: c -> [Term c v] -> Term c v
Run Code Online (Sandbox Code Playgroud)

如果我要的类型的术语结合Term c VoidTerm c Int,这应该是可能的,因为我有第一项不包含任何变量的保证.因此,我可以编写函数:

castVar :: Term c Void -> Term c v
castVar (Var i   ) = absurd i
castVar (Con x xs) = Con x (map castVar xs)
Run Code Online (Sandbox Code Playgroud)

然而,实际运行这个函数真是太遗憾了,因为我知道它实际上并没有改变任何东西.添加以下编译指示是否安全:

{-# NOINLINE castVar #-}
{-# RULES "castVar/id" forall x. castVar x = x; #-}
Run Code Online (Sandbox Code Playgroud)

这会实际达到预期的效果吗?

有更好的方法吗?

cch*_*ers 7

不,这不行.只有在检查类型时才会应用重写规则.在这种情况下,规则只会在您运行时触发castVar :: Term c Void -> Term c Void,这不是很有帮助.(有关重写规则的更多信息,请参阅https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/rewrite-rules.html)

你想要的是强迫这种类型.它的安全要做到这一点,因为你知道有没有VoidTerm.您可以通过导入做到这一点Unsafe.Coerce,并castVar = unsafeCoerce或作出Term的一个实例Functor(你可以得到它为这个简单的版本),并使用unsafeVacuousData.Void.Unsafe.