断言数据构造函数是单射的

时间:2013-10-18 07:04:53

标签: haskell

我有以下数据类型:

{-# LANGUAGE GADTs, KindSignatures, ScopedTypeVariables, DataKinds #-}

import GHC.TypeLits
import Unsafe.Coerce

data Var (i :: Nat) where
    Var :: (Num a, Integral a) => a -> Var i
    {- other constructors .... -}

然后我有Num个实例:

instance Num (Var i) where
    (Var a) + (Var b) = Var (a + b)

当然这不起作用。类型a由构造函数隐藏,因为Var的类型为forall (i :: Nat) a. Num a => a -> Var i。另请注意,Var构造函数不能直接使用; Var由智能构造函数创建,保证Var i0 ~ Var i1 => a0 ~ a1。 Var的类型不能是Var i a;重点是隐藏用户的类型。

我怎样才能告诉类型系统,我已经'证明'是真的,即Var i0 ~ Var i1 => a0 ~ a1。目前我正在使用unsafeCoerce

(Var (a :: n)) + (Var b) = Var (a + (unsafeCoerce b :: n))

我意识到unsafeCoerce在两个类型相等的断言中,但我想尝试在类型级别上进行此断言,因此导出构造函数并不安全。不安全我的意思是以下是可能的:

>instance Show (Var i) where {show (Var a) = "Var " ++ show a}
>import Data.Word
>Var (1000 :: Word16) + Var (255 :: Word8)
Var 1255
>Var (255 :: Word8) + Var (1000 :: Word16)
Var 231

1 个答案:

答案 0 :(得分:5)

一种可以说服类型系统的方法是在类型级别提供映射函数Of :: i -> a。如果i ~ i' => Of i ~ Of i',这很简单。这是您的程序的修改版本

{-# LANGUAGE GADTs, KindSignatures, ScopedTypeVariables, DataKinds, TypeFamilies, FlexibleContexts #-}

import GHC.TypeLits
import Unsafe.Coerce

type family Of :: Nat -> *

data Var (i :: Nat) where
    Var :: (Num (Of i), Integral (Of i)) => (Of i) -> Var i

instance Num (Var i) where
    (Var a) + (Var b) = Var (a + b)

这样做的缺点是你必须提供显式映射。可能有更优雅的方式来捕捉你在类型级别的约束,我等着看到更多开明的人提供洞察力。