尝试在Haskell中构建词法分析程序

尝试在Haskell中构建词法分析程序,haskell,Haskell,我正在开始这个项目,但进展甚微。我只是从haskell开始,所以我只想使用我自己实现的函数,这样我就能把我的大脑投入到行动中 我想要两个字符串列表,一个表示代码,另一个为给定语言保留名称。我希望能够从第一个列表中筛选出所说的单词 resNames = ["function","while","for","const","let","this","true","false",";","=", "()", "var"] findVal :: [String]->String->[St

我正在开始这个项目,但进展甚微。我只是从haskell开始,所以我只想使用我自己实现的函数,这样我就能把我的大脑投入到行动中

我想要两个字符串列表,一个表示代码,另一个为给定语言保留名称。我希望能够从第一个列表中筛选出所说的单词


resNames = ["function","while","for","const","let","this","true","false",";","=", "()", "var"]

findVal :: [String]->String->[String]
findVal z " " = z
findVal [] value = []
findVal (x:y) value = if x == value then findVal y value
                      else x:(findVal y value) 

filterResNames :: [String]->[String]->[String]
filterResNames z [] = z
filterResNames [] z = []
filterResNames (x:y) (u:v) = if x== u then findVal (x:y) (u) else x:(filterResNames y (u:v))```

This obviously doesn't work because the program stops as soon as it finds a match...

如果我正确理解你的想法,这可能是一个可行的解决方案:

resNames = ["function","while","for","const","let","this","true","false",";","=", "()", "var"]

-- Determine whether an element is in a list
findVal :: String->[String]->Bool
findVal _ [] = False
findVal x (namesH:namesT) =
  if x == namesH
  then True
  else (findVal x namesT) 

-- Loop over input list and for each element, if not in reserved list, add to accumulator
filterResNamesAcc :: [String]->[String]->[String]->[String]
filterResNamesAcc _ [] acc = acc
filterResNamesAcc [] _ acc = acc
filterResNamesAcc (inH:inT) names acc =
  if (findVal inH names)
  then (filterResNamesAcc inT names acc)
  else (filterResNamesAcc inT names (inH:acc))

-- Invoke filterResNamesAcc with empty accumulator
filterResNames :: [String]->[String]->[String]
filterResNames inL names = reverse (filterResNamesAcc inL names [])

main = do
   print (filterResNames ["hello", "for", "the", "world"] resNames)
我们在这里使用的是函数式语言中使用的典型累加器模式。
filterResNamesAcc
的“问题”是,使用
预先添加到累加器会导致结果被反转,因此调用
reverse

左“给读者”:

  • 实现你自己的反向或想出一个更复杂的折叠模式,不需要它
  • 更改
    filterResNames
    的签名以获取单个字符串并进行标记化

  • 最好通过手工实现来学习标准库,因此您可以:

  • 在实施过程中弄脏你的手,并进行一些练习
  • 从标准库中学习所有这些有用的工具,当您足够熟悉它们时,可以直接使用这些工具
  • 因此,您需要在某些条件下“过滤”某些列表,这就是著名的
    filter
    标准函数:

    filter :: (a -> Bool) -> [a] -> [a]
    filter _ [] = []
    filter cond (x : xs) = let tail = filter cond xs
                           in if cond x
                              then x:tail
                              else tail
    
    elem :: (Eq a) => a -> [a] -> Bool
    elem _ [] = False
    elem x (y:ys) = x == y || elem x ys
    
    这里我们只留下这样的
    x
    ,它们具有
    cond x
    等于
    True
    。例如,
    偶数过滤[1..10]==[2,4,6,8,10]

    我们将使用它只过滤掉保留字。现在我们需要构造条件。所以我们需要检查保留列表中是否有一个单词。这是标准的
    elem
    功能:

    filter :: (a -> Bool) -> [a] -> [a]
    filter _ [] = []
    filter cond (x : xs) = let tail = filter cond xs
                           in if cond x
                              then x:tail
                              else tail
    
    elem :: (Eq a) => a -> [a] -> Bool
    elem _ [] = False
    elem x (y:ys) = x == y || elem x ys
    
    在这里,我们需要这样的调用,即“您只能将其用于支持
    ==
    检查的类型”
    String
    就是这种情况,因此您可以这样使用它:

    elem "if" ["for", "if", "else", "function"] == True
    
    现在,我们已经准备好使用我们的工具获得结果:

    filterResNames :: [String] -> [String] -> [String]
    filterResNames toCheck resNames = filter (`elem` resNames) toCheck
    
    这里我们使用一些技巧:

  • 如果名称周围有`(反勾号)符号,则两个参数的每个函数都可以用作运算符,如
    +
    ==
    elem x lst
    相当于
    x`elem`lst

  • 如果采用形式为
    x someOperator y
    的表达式,将其括在括号中
    (x someOperator y)
    ,并省略其中一个操作数
    (someOperator y)
    ,则会自动获得一个函数,该函数将此“省略”的操作数“粘贴”到表达式中。一些例子:

    • (+1)
      -取一个值并将其增加1
    • (==x)
      -取一个值并检查它是否等于
      x
    • (2^)
      -给定一些
      n
      获得
      n
      的2次方
    • (`elem`someList)
      -获取一个值并检查它是否包含在
      someList

  • 对不起,你有两个答案(一个是我的),你会接受其中任何一个吗?