GHC REWRITE pragma 是否必须保留类型?
Do GHC REWRITE pragmas have to be type preserving?
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 Void
和 Term 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; #-}
这真的能达到预期的效果吗?
有更好的方法吗?
不,这行不通。仅当类型检查时才应用重写规则。在这种情况下,规则只会在您 运行 castVar :: Term c Void -> Term c Void
时触发,这不是很有帮助。 (有关重写规则的更多信息,请参阅 https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/rewrite-rules.html)
你要的是强制类型。这样做是安全的,因为您知道 Term
中没有 Void
。您可以通过导入 Unsafe.Coerce
和 castVar = unsafeCoerce
来执行此操作,或者使 Term
成为 Functor
的实例(您可以为这个简单版本派生它)并使用 unsafeVacuous
来自 Data.Void.Unsafe
.
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 Void
和 Term 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; #-}
这真的能达到预期的效果吗?
有更好的方法吗?
不,这行不通。仅当类型检查时才应用重写规则。在这种情况下,规则只会在您 运行 castVar :: Term c Void -> Term c Void
时触发,这不是很有帮助。 (有关重写规则的更多信息,请参阅 https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/rewrite-rules.html)
你要的是强制类型。这样做是安全的,因为您知道 Term
中没有 Void
。您可以通过导入 Unsafe.Coerce
和 castVar = unsafeCoerce
来执行此操作,或者使 Term
成为 Functor
的实例(您可以为这个简单版本派生它)并使用 unsafeVacuous
来自 Data.Void.Unsafe
.