[英]Is it possible to store a GADT inside a State monad transformer?
Say that I have got a GADT like this: 说我有这样的GADT:
data Term a where
Lit :: a -> Term a
Succ :: Term Int -> Term Int
IsZero :: Term Int -> Term Bool
If :: Term Bool -> Term a -> Term a -> Term a
Is it possible to store Succ (Lit 2)
and IsZero (Succ (Lit 2))
inside the State monad transformer, as a value of the internal state? 是否可以将状态monad变压器内的
Succ (Lit 2)
和IsZero (Succ (Lit 2))
为内部状态的值?
The issue here being those two are of different types, and I don't know how the s
of StateT sma
should be typed. 这里的问题是那两个是不同类型的,我不知道应该如何键入
StateT sma
的s
。
Edit: ATerm
solved the initial question of how to store different GADT
in the state, the issue now is since the type is lost it seemed impossible to compare the old and new state. 编辑:
ATerm
解决了如何在州内存储不同GADT
的初始问题,现在的问题是由于类型丢失,似乎无法比较新旧状态。
Edit: Final answer. 编辑:最终答案。
After going back and forth with @luqui, here's the full code snippet that answers this question. 和@luqui一起来回走动之后,这里是回答这个问题的完整代码片段。
Feel free to fork this repl and have a try. 随意分叉这个repl并试一试。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
import Data.Typeable
data Term a where
Lit :: a -> Term a
Succ :: Term Int -> Term Int
IsZero :: Term Int -> Term Bool
If :: Term Bool -> Term a -> Term a -> Term a
deriving instance (Eq a) => Eq (Term a)
data ATerm where
ATerm :: (Typeable a, Eq a) => Term a -> ATerm
instance Eq ATerm where
ATerm t == ATerm u
| Just t' <- cast t = t' == u
| otherwise = False
main :: IO ()
main = return ()
Yes, you can use an existential 是的,你可以使用存在主义
data ATerm where
ATerm :: Term a -> ATerm
which is a monotype that stores "a Term
of any type". 这是一个存储“任何类型的
Term
”的单一型。
However you should be aware that you will lose the type information, which I have a hunch will not cause a problem in your case. 但是你应该知道你会丢失类型信息,我预感不会导致你的问题。 If you do need to recover it, you will need to add some
Typeable
constraints or some other trick—hard to say without more context on what you are doing. 如果你确实需要恢复它,你将需要添加一些
Typeable
约束或其他一些技巧 - 如果没有更多关于你正在做的事情的上下文。
EDIT 编辑
To get the type information back, you will need to include it in ATerm
要获取类型信息,您需要将其包含在
ATerm
data ATerm where
ATerm :: (Typeable a, Eq a) => Term a -> ATerm
Sadly, this change might cause the Typeable
constraint to infect a fair amount of your code. 遗憾的是,此更改可能会导致
Typeable
约束感染相当数量的代码。 That's just how it goes. 这就是它的方式。 We also include
Eq a
, since if we are comparing ATerms
and do find that their types are the same, we will need to compare on that type. 我们还包括
Eq a
,因为如果我们比较ATerms
并确实发现它们的类型相同,我们将需要对该类型进行比较。
Then to compare two ATerm
s, you first need to compare their types, then their values. 然后要比较两个
ATerm
,首先需要比较它们的类型,然后比较它们的值。 This can be done with the Typeable
library. 这可以使用
Typeable
库完成。
instance Eq ATerm where
ATerm t == ATerm u
| Just t' <- cast t = t' == u
| otherwise = False
Luckily, your Term
GADT doesn't hide any types. 幸运的是,你的
Term
GADT并没有隐藏任何类型。 If you had a case like, for example 例如,如果你有一个案例
data Term a where
...
Apply :: Func a b -> Term a -> Term b
you would need to add Typeable
also to any hidden variables (variables that don't appear in the result type) 您还需要将
Typeable
添加到任何隐藏变量(未出现在结果类型中的变量)
Apply :: (Typeable a) => Func a b -> Term a -> Term b
Roughly, if you want to compare types, you need to have a Typeable
constraint on them somewhere. 粗略地说,如果要比较类型,则需要在某处对它们进行
Typeable
约束。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.