首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异构GADT列表

异构GADT列表
EN

Stack Overflow用户
提问于 2018-03-27 17:41:03
回答 1查看 425关注 0票数 2

我有一个GADT,如下所示

代码语言:javascript
复制
data MyTypes
    = MyInt
    | MyDouble

data Test (t :: MyTypes) where
    A :: Int -> Test 'MyInt
    B :: Double -> Test 'MyDouble

这允许我在类型级别上跟踪Test值中包含的值,这样我也可以执行以下操作

代码语言:javascript
复制
data Test2 (t :: MyTypes) where
    A2 :: Test 'MyInt -> Test2 'MyInt
    B2 :: Test 'MyDouble -> Test2 'MyDouble

传递信息。

但是,如果我想要一个具有不同Test值的MyTypes列表,如

代码语言:javascript
复制
myData :: [Test (t :: MyTypes)]
myData =
    [ A (3 :: Int)
    , B (5.0 :: Double)
    ]

我得到了预期的‘t’ is a rigid type variable bound错误消息。

我试图使用存在类型来克服刚性类型变量的问题,但随后我失去了传递有关MyType的类型级别信息的能力。

我该如何处理这个问题呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-27 21:13:50

这里的解决方案是存在主义的:

代码语言:javascript
复制
data Test a where
  A :: Int -> Test Int
  B :: Double -> Test Double

data SomeTest where
  SomeTest :: Test a -> SomeTest

myData :: [SomeTest]
myData =
  [ SomeTest (A (3 :: Int))
  , SomeTest (B (5.0 :: Double))
  ]

这只是改变了使用这种类型的方式。您可以通过模式匹配恢复类型信息:

代码语言:javascript
复制
consume :: Test a -> Int
consume (A a) = a + 1
consume (B b) = truncate b

map (\ (SomeTest x) -> consume x) myData :: [Int]

使用RankNType,您可以使用恢复类型的延续来展开它:

代码语言:javascript
复制
test :: (forall a. Test a -> r) -> SomeTest -> r
test k (SomeTest x) = k x

test (\ x -> case x of
  A a -> a + 1 {- ‘a’ is known to be ‘Int’ here -}
  B b -> truncate b {- ‘b’ is known to be ‘Double’ here -})
  :: SomeTest -> Int

没有任何类型限制的存在主义通常是有用的,当您使用它将多个事物打包到某种“模块”中时,它们都必须就类型达成一致,但这种类型从外部来看是不透明的。这限制了使用者可以执行的操作--例如,考虑一对请求和一个变量来存储该请求的结果:

代码语言:javascript
复制
data SomeRequest where
  SomeRequest :: IO a -> IORef a -> SomeRequest

fetchRequests :: [SomeRequest] -> IO ()
fetchRequests = traverse_ fetchRequest
  where

    -- ‘fetchRequest’ controls the fetching strategy (sync/async)
    -- but can’t do anything with the fetched value
    -- other than store it in the ‘IORef’.
    fetchRequest :: SomeRequest -> IO ()
    fetchRequest (SomeRequest request result) = do
      value <- request
      writeIORef result value

如果您有一个完全多态的类型,比如:

代码语言:javascript
复制
data Test a where
  Test :: a -> Test a

然后,您可以通过添加类型约束来恢复有关该类型的更多有趣信息。例如,如果您想要完整的动态信息,可以使用Typeable获得它。

代码语言:javascript
复制
data SomeTest where
  SomeTest :: Typeable a => Test a -> SomeTest

test :: (forall a. Typeable a => Test a -> r) -> SomeTest -> r
test k (SomeTest x) = k x

test (\ (Test a) -> case cast a of
  Just a' -> (a' :: Int) + 1
  Nothing -> case cast a of
    Just a' -> length (a' :: String)
    Nothing -> 0)

大多数情况下,您可以使用比此更小的类型类型,这取决于您实际需要的操作。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49519247

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档