haskell - 展开存在量化的 GADT
问题描述
我有一个Value
按其类型标记的自定义值类型ValType
:
data ValType
= Text
| Bool
data Value (tag :: ValType) where
T :: Text -> Value 'Text
B :: Bool -> Value 'Bool
我想定义一个解开存在量化的函数Value
,即它应该具有以下类型签名:
data SomeValue = forall tag. SomeValue (Value tag)
unwrap :: SomeValue -> Maybe (Value tag)
我可以单独定义 unwrap 'Bool
,'Text
但是如何定义多态unwrap
?
解决方案
你真的不能在这里避免一个类型类或等价物。unwrap
,因为您已经编写了它的类型,所以无法知道它正在寻找哪个标签,因为类型已被删除。惯用的方法使用单例模式。
data SValType v where
SText :: SValType 'Text
SBool :: SValType 'Bool
class KnownValType (v :: ValType) where
knownValType :: SValType v
instance KnownValType 'Text where
knownValType = SText
instance KnownValType 'Bool where
knownValType = SBool
unwrap :: forall tag. KnownValType tag => SomeValue -> Maybe (Value tag)
unwrap (SomeValue v) = case knownValType @tag of
SText
| T _ <- v -> Just v
| otherwise -> Nothing
SBool
| B _ <- v -> Just v
| otherwise -> Nothing
与IsType
您自己答案的类别不同,它KnownValType
允许您从模式匹配中获取类型信息和值标记。因此,您可以更广泛地使用它来处理这些类型。
对于你typeOf
的情况足够的情况,我们可以毫不费力地编写它:
typeOf :: KnownValType a => Proxy a -> ValType
typeOf (_ :: Proxy a) = case knownValType @a of
SBool -> Bool
SText -> Text
推荐阅读
- java - @Transactional 没有按预期工作,因为需要“save”方法保存到数据库
- mongodb - 如何在多租户 grails 应用程序(MongoDB)中引用其他数据库中的其他表?
- pandas - 您如何将搬运工词干分析器应用于熊猫 df?
- javascript - 从服务端向客户端发送响应(Node.js、javascript)
- python - 如何从另一列所有值创建新列名,并通过熊猫数据框中的另一列创建新列名?
- pandas - 根据列和行值合并数据框
- swift - 如何在我的自定义代码中将自动填充功能设为默认?
- csv - 如何将csv文件拆分为多个yaml文件
- r - 季度数据规模错误的年份
- sql - 水平多列 - 按月分组