GHC REWRITE pragma必须保持类型吗?

时间:2015-04-26 12:37:54

标签: haskell ghc pragma

import Data.Void (Void,absurd)

说我有一个小学期的语言:

data Term c v where
  Var :: v               -> Term c v
  Con :: c -> [Term c v] -> Term c v

如果我想组合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)

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

{-# NOINLINE castVar #-}
{-# RULES "castVar/id" forall x. castVar x = x; #-}

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

有更好的方法吗?

1 个答案:

答案 0 :(得分:7)

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

你想要的是强迫这种类型。这样做是安全的,因为您知道Void中没有Term。您可以通过导入Unsafe.CoercecastVar = unsafeCoerce或将Term设为Functor的实例来实现此目的(您可以为此简单版本派生它)并使用unsafeVacuous来自Data.Void.Unsafe