问题描述
我需要为要统一术语的应用程序重命名变量,而我过去的做法是使用类似(gensym)的功能,并用gensym-ed替换var的名称。名称,通常修饰为字符串。我还需要比较变量的名称。
因此(rename (logvar1 "foo"))
将返回(logvar1 "#:23322)
-或其他任何值,我可以掌握“#:23322”,并对照条款中的任何其他逻辑变量检查它。
在haskell中,我不确定该怎么做。我发现Data.Unique,它返回一个IO唯一。 唯一是Eq的一部分,但IO唯一不是。
m = newUnique
n = newUnique
test :: (Monad m,Eq a) => m a -> m a -> m Bool
test u1 u2 = do
v1 <- u1
v2 <- u2
if v1 == v2 then return True else return False
我想返回True of False,而不是IO True或IO False。
当然,您不能总是得到想要的东西.....
感谢您的帮助。我了解为什么会有IO,但我不确定在我想比较的程序的其余部分中如何最好地处理它
解决方法
该库的想法是,在程序中需要生成唯一标签的部分中,您使用IO。以后,当您只需要比较唯一标签时,就不需要IO
main :: IO ()
main = do
x <- newUnique
y <- newUnique
print $ same x y
same :: Eq a => a -> a -> Bool
same = (==)
我已经为(==)
定义了一个别名,目的是为了清楚地表明,在比较中不涉及IO,仅在标签创建中。
您可以使用State而不是IO来执行相同的操作,并以此实现自己的gensym。这种方法的优点是您可以获得更透明的gensyms,例如给他们一个名字和一个唯一的数字,而不只是一个不透明的唯一标识符。
,我认为您的test
签名没有意义。您不应该比较单子数值-而是比较唯一值的 generators ,而不是唯一值本身。
您要做需要一个monad来生成唯一密钥,因为非monadic生成器无法知道其他已经生成的密钥。但是在IO
中执行此操作会有些过分,因此使用专用的monad会更好。
prim-uniq
offers such generators:它们可以像IO
一样在Data.Unique.newUnique
中使用,也可以在ST
monad中本地使用。
type VarId s = Uniq s
data Expr s = LogVar (VarIs s)
| ...
deriving (Eq)
rename :: (PrimMonad m,s ~ PrimState m)
=> Expr s -> m (Expr s)
rename (LogVar _) = LogVar <$> getUniq
rename ... = ...