Haskell Data.Unique

问题描述

我需要为要统一术语的应用程序重命名变量,而我过去的做法是使用类似(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 ... = ...