禁止赋值

时间:2017-06-18 13:21:49

标签: haskell purescript unification impredicativetypes rank-n-types

我正在尝试使用类型级别的权限系统,并且我试图禁止分配不是源自相同"来源"的值,即:

data A = A { a :: Value, b :: Value }

modify :: A -> A
modify (A v) = A $ v { a = v.a } -- should work
modify (A v) = A $ v { a = v.b } -- should *NOT* work

我已尝试过N级(或不可预测的?)类型:

type Value = forall a. Value a ...

但两种情况都统一起来。如果我约束a

type Value = forall a. Unique a => Value a ...
两个案例都没有。有没有办法实现这样的目标?在Haskell有可能吗?

(注意:Value构造函数不会公开,即无法创建独立的Value。)

1 个答案:

答案 0 :(得分:4)

正如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。但这意味着绝对无法从Value中提取实际值。您仍然可以为ValueFunctorApplicative实例化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