首页 文章

Haskell getArgs更改数据类型

提问于
浏览
0

我正在尝试为Haskell模块构建一个main函数,该模块将从用户处获取正则表达式并在SimplifyRegExp函数中使用它,但这需要RegExp类型的输入:

data RegExp sy  = Empty                              
            | Epsilon                            
            | Literal   sy                       
            | Or        (RegExp sy) (RegExp sy)  
            | Then      (RegExp sy) (RegExp sy)  
            | Star      (RegExp sy)              
   deriving (Read, Eq)

如何将字符串转换为RegExp类型?

如果我将程序加载到GHCi上,那么我可以直接调用该方法,如下所示:

*Language.HaLex.RegExp> simplifyRegExp(Star (Star a))
'a'*

但我想这样做,所以我可以在命令提示符中只传递一个参数的程序,它将打印结果类似于以下(哪个当然不起作用):

main = do
  n <- getArgs $ head
  print (simplifyRegExp(n))

1 回答

  • 2

    您可以为您的类型定义 Read 实例并使用它

    data RegEx sy = ...
                  deriving Read
    

    然后使用 readMay

    import Text.Read
    ...
    
    main = do
      regexp <- (readMay . head) `fmap` getArgs
      case regexp of
       Just r -> ...
       Nothing -> putStrLn "Parse error!"
    

    但这在两个方面有点脆弱 . 首先是 read 是部分功能!如果正则表达式生成错误,您的程序将会爆炸 . 其次,使用您的默认 read 实例强制您的正则表达式的内部表示到您的用户!如果这是一个严肃的项目,你最好做一些实际的解析 .

    幸运的是,Haskell有一些非常棒的解析库 . 一些最着名的包括parsecattoparsec .

    parsec解析器的一个例子可能是

    import Text.Parsec
    import Text.Parsec.String
    
    import Control.Applicative
    
    parseStar :: Parsec (RegExp Char)
    parseStar = Star <$> (parseRe <* char '*')
    
    parseLiteral :: Parsec (RegExp Char)
    parseLiteral = Literal <$> noneOf "*()"
    
    parseOr :: Parsec (RegExp Char)
    parseOr = Or <$> parseRe <*> (char '|' *> parseRe)
    
    parseThen :: Parsec (RegExp Char)
    parseThen = Then <$> parseRe <*> parseRe
    
    ....
    

相关问题