包含GADT的载体

时间:2015-11-16 11:20:05

标签: haskell vector existential-type gadt data-kinds

我正在学习关于存在主义量化和GADT以及KindSignatures等的一切。为此,我尝试提出一些小程序,帮助我更好地理解一切。

现在我有了这个小片段(实际上是编译的,所以你可以自己尝试,需要 vector mtl 包)并且想知道它是否我有可能做我想要完成的事情或指导我如何使它工作

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
import Control.Monad.State.Lazy
import qualified Data.Vector as V

data MenuItem = ListS | ActionS | SliderS

data MenuItemReference (a :: MenuItem) (n :: *) where
       MenuListSReference :: Int -> MenuItemReference ListS Int
       MenuActionSReference :: Int -> MenuItemReference ActionS Int
       MenuSliderSReference :: Int -> MenuItemReference SliderS Int

data MyState = MyState { vec :: forall a. V.Vector (MenuItemReference a Int) }

newMyState :: MyState
newMyState = MyState { vec = V.empty }

listRef :: MenuItemReference ListS Int
listRef = MenuListSReference 5

actionRef :: MenuItemReference ActionS Int
actionRef = MenuActionSReference 3

myComputation :: State MyState ()
myComputation = do
    addItem listRef
    addItem actionRef
    return ()

addItem :: forall a. MenuItemReference a Int -> State MyState ()
addItem menuItemRef = do
    s <- get
    put (s { vec = (vec s) `V.snoc` menuItemRef })

main :: IO ()
main = do
    print $ evalState myComputation newMyState

正如你所看到的,我正在尝试在其中获取一个MenuItemReferences的向量...我做错了什么因为我现在得到的错误:

Couldn't match type ‘a’ with ‘a1’
  ‘a’ is a rigid type variable bound by
      the type signature for
        addItem :: MenuItemReference a Int -> State MyState ()
      at Main.hs:34:19
  ‘a1’ is a rigid type variable bound by
       a type expected by the context: V.Vector (MenuItemReference a1 Int)
       at Main.hs:37:10
Expected type: MenuItemReference a1 Int
  Actual type: MenuItemReference a Int
Relevant bindings include
  menuItemRef :: MenuItemReference a Int (bound at Main.hs:35:9)
  addItem :: MenuItemReference a Int -> State MyState ()
    (bound at Main.hs:35:1)
In the second argument of ‘V.snoc’, namely ‘menuItemRef’
In the ‘vec’ field of a record

有人可以解释错误背后的原因以及我如何处理(如果可能的话)我想要完成的事情。

1 个答案:

答案 0 :(得分:1)

为什么不

data MenuItemReference = 
    MenuListSReference Int | 
    MenuActionSReference Int | 
    MenuSliderSReference Int

然后?

使用的构造函数已经注释了该值。您不需要注入幻像类型,因为信息已经存在。

此外,这样做需要启用GHC({-# LANGUAGE ImpredicativeTypes #-})来实际支持impredicative polymorphism构建Vector [forall a. MenuItemReference a Int]并以多态方式使用它。虽然它确实支持这一点,但支持被描述为“最好是脆弱的,最糟糕的是破坏了”#34;。

附注[{3}}解释了如何使用newtypeRankNTypes来消除不可预测的类型。这确实需要您引入一层newtype,但是。