正如 user2407038 提到的,您可以使用幻像类型来做您想做的事。
{-# LANGUAGE DataKinds, GADTs, KindSignatures #-}
data ValueType = A | B
data Value :: ValueType -> * where
Value :: Int → Value t
data V = V { a :: Value A, b :: Value B }
modify ∷ V -> V
modify v = v { a = a v } -- no error
modify v = v { a = b v } -- Couldn't match type ‘'B’ with ‘'A’
但是,有一个解决方法:
modify ∷ V -> V
modify v = v { a = Value $ getBValue (b v) }
where getBValue (Value x) = x
getBValue
但是,如果您隐藏Value
构造函数(通过不导出它),您可以阻止用户写入。但这意味着绝对没有办法从 a 中提取实际值Value
。您仍然可以为 , 实例化Value
,以便Functor
您可以直接使用这些包装的值。但是您必须更改为更通用的形式。这是一个例子:Applicative
Monad
Value
data Value :: ValueType -> * -> * where
Value :: a -> Value t a
instance Functor (Value t) where
fmap f (Value x) = Value (f x)
instance Applicative (Value t) where
pure = Value
Value f <*> Value x = Value (f x)
instance Monad (Value t) where
Value x >>= f = f x