2008年12月6日星期六

Write Yourself a Scheme in 48 Hours/Parsing(二)

囧然发现,代码的排版总是会丢失缩近。这个当然不能怪发芽网的服务不好,因为直接可以看到的是blogger的有些模板就有问题。这东西的可视化编辑器又慢,功能又不全。

我现在用gmail的内置编辑器,不过这东西也不能算好用,它没办法编辑HTML源码。网上有人贴过muse向blogger发布的代码。等这个坑填完我肯定是要再去弄muse的,到时候不妨拿来看看(话说,muse真是个好东西吖)。

上次讲到了如何利用 oneOf 函数提取代码中的符号。因为我们没有处理空格,如果符号前有多的空格,就会出错了。

作者的解释是,Parsec的spaces不符合他的要求,虽然另有一个lexeme可用,但是这里我们可以自己定做一个。

Haskell语言: Parsing 代码片段四

spaces :: Parser ()
spaces = skipMany1 space

这东西其实比我猜想的简单多了,还是直接拿了一个东西来用,跟oneOf换汤不换药嘛。

现在我们修改一下readExpr,把这个新组件串进去。

readExpr input = case parse (spaces >> symbol) "lisp" input of
Left err -> "No match: " ++ show err
Right val -> "Found value"

这里我没用发芽网的服务,主要是给大家看到红字标明的修改标记。如果没有心理准备,大概会被这个简单的用法小小震惊一下。>>符号是 Monad 的四个标准运算符之一,"bind"操作符。通过它,我们把skipMany1 space传入symbol中,组成一个新的parser Monad。这里作者特别有介绍,不同的Monad,它的bind行为可能完全不同。具体的情况一定要阅读文档来确定。在Parser Monad中,它就是尝试匹配第一个组件,不行再匹配第二个,直至匹配成功或最终返回错误。

Monad一个非常强大的地方就在于这种组合能力,这与OO中的继承或接口复用还是有很大不同的。等这个教程跟完,如果我觉得我对Monad有些了 解了,可能会写一些关于Monad的文章。其实关于Monad,国内已经有一篇非常强大的文章,来自Javaeye社区的Trustno1。简单介绍一下 背景,这大佬多年以前在程序员上以"恶魔吹着笛子来"为署名写了一系列Python教程,这几篇文章将我和很多程序员引入了Python领域。至于 Lee……不需要我多介绍了吧:)。

这一小节的完整代码:

Haskell语言: Parsing第二部分的完整代码

module Main where

import System.Environment
import Text.ParserCombinators.Parsec hiding (spaces)

symbol :: Parser Char
symbol = oneOf "!#$%&|*+-/:<=>?@^_~"

spaces :: Parser()
spaces = skipMany1 space

readExpr :: String -> String
readExpr input = case parse (spaces >> symbol) "lisp" input of
Left err -> "No match: " ++ show err
Right val -> "Found value"

main :: IO ()
main = do args <- getArgs
putStrLn (readExpr (args !! 0)

没有评论: