次のデータ型があります。
{-# 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
コンストラクターによって隠されています。また、コンストラクターは直接使用することを意図していないことに注意してください。s は、 を保証するスマート コンストラクターによって作成されます。Var の型を にすることはできません。ポイントは、タイプをユーザーから隠すことです。Var
forall (i :: Nat) a. Num a => a -> Var i
Var
Var
Var i0 ~ Var i1 => a0 ~ a1
Var i a
型システムに、私が真であると「証明」したこと、つまりそれをどのように伝えることができますかVar i0 ~ Var i1 => a0 ~ a1
。現在私は使用していunsafeCoerce
ます:
(Var (a :: n)) + (Var b) = Var (a + (unsafeCoerce b :: n))
unsafeCoerce
2 つの型が等しいというアサーションであることは理解していますが、コンストラクターのエクスポートが危険にならないように、このアサーションを型レベルで試してみたいと思います。安全でないということは、次のことが可能であることを意味します。
>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