所以,我正在尝试创建一个函数来重命名Lambda Calculus表达式中的变量,但我似乎无法弄清楚如何获取尚未使用的Char,因此我可以将其设置为新名称变量。
我已经有一个包含所有Chars的列表,这些Chars被用作变量的名称,所以我需要的只是一个接收此列表的函数e返回一个不同的Char,即一个未使用的。
这样的功能:
getNewVarName :: [Char] -> Char
我没有真正使用列表或Haskell,所以我希望你可以原谅我这个愚蠢的问题。
//编辑1
-- acceptableNames is passed as the second argument to getNewVarName
acceptableNames = ['a'..'z'] ++ ['A'..'Z']
getNewVarName :: [Char] -> [Char] -> Char
-- vars is the list with all the names actually being used
-- acceptable == acceptableNames
getNewVarName vars acceptable
| (not(null acceptable)) = let e = head acceptable
in if(elem e vars)
then getNewVarName vars (tail acceptable)
else e
| otherwise = '$' -- returns '$' just if all acceptableNames are used up
基本上,它的作用是返回acceptableNames
中未包含在vars
中的第一个字符。显然,它有效。
我意识到必须有很多更好的方法来做到这一点,但是,考虑到我对Haskell的了解,这就是对我有意义的方式。
请让我知道我可以改进此代码的任何方法。
//编辑2
在这种情况下,@ luqui的答案非常有效。比我的解决方案更简单。答案 0 :(得分:2)
对于二次时间算法(以Haskell风格制作通用):
import Data.List ((\\))
getNewVarName :: (Eq a) => [a] -> [a] -> a
getNewVarName possibleVars varsInUse = head (possibleVars \\ varsInUse)
其中(\\)
是列表差异运算符。
如果使用Data.Set
来存储可能的变量和使用的变量而不是列表,那么这个相同的算法只需要花费O(n log n)。您可以使用trie来获得线性时间,但这只是变得愚蠢。如果你真的关心速度,你应该使用supply新变量。
答案 1 :(得分:1)
您可以在刚刚获得免费角色时保存其状态。
所以,你需要这样的功能:
getNewVarName :: [Char] -> (Char, [Char])
getNewVarName (x:xs) = (x, xs)
getNewVarName _ = error "Ups, here are not free characters."
let
(name1, xs') = getNewVarName xs
(name2, xs'') = getNewVarName xs'
in ...
你可以看到this question。