Haskell:如何从列表中获取不同的字符?

时间:2016-12-07 22:04:18

标签: haskell

所以,我正在尝试创建一个函数来重命名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的答案非常有效。比我的解决方案更简单。

2 个答案:

答案 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