近来一直在看haskell发现函数式编程还是挺好玩的.参考资料是`Learn You a Haskell`和`Programing in Haskell`,第一本书前部分有中文翻译版,看了3-四遍有点感觉.后面还没看,第二本有视频,有对应的ppt习题.第二本不厚就1百多页.看到第八章时郁闷了.function parsers.就是语法分析,不过这边实现的还是比较简单的书中实现了+*() 的解析,习题要自己写-/的解析.
来来回回看了几遍,记下学习过程吧(可能有些不太正确)..
--type Parser = String->Tree
--type Parser = String->(Tree,String)
--type Parser = String->[(Tree,String)]
type Parser a= String ->[(a,String)]
这里是定义了一个类型Parser,第一次是直接将 String转为Tree,但是不可能一次全部转换所以就保留了后面的String(第二种),但是肯能第一次都转换错了,所以要表示错误结果,可以使用Maybe类型但是这边使用的列表,错误时就直接转为空列表,正确就转为`一元`的列表(第三种),转换时不可能总是转为Tree于是这里就泛型了下 用a表示可以转换后的类型
1.基本Parser
return :: a->Parser a
return v = \inp->[(v,inp)] -- return v inp = [(v,inp)](也可以这样写)
--sample: return 1 "abc" = [(1,"abc")]
return 是永远返回v值的Parser(不太好讲)
failure::Parser a
failure = \inp -> []
failure永远是返回[]类型是Parser 的类型
item::Parser Char
item = \inp -> case inp of
[]->[]
(x:xs)-[(x,xs)]
item读入String 并返回第一个 Char 如果String为空则失败
parse ::Parser a -> String->[(a,String)]
parse p inp = p inp
parse是讲Parser 类型变为可输出(不太懂,但是值了Parser a输出是有错误的,如 failure a 虽然是[]但是不可输出)
2.序列检测
(>=)Parser a->Parser b->Parser (a,b)
p >>= f = \inp -> case parse p inp of
[]->[]
[(v,out)] -> parse (f v) out
p的类型是Parse a
f的类型是Parse b 如果p发生错误 则返回[] 否则 再由f检测(这个也不懂)
p::Parser (Char,Char)
p = do x<- item
item (或者 z<-item)
y<-item
return (x,y)
p的作用是将[x1,x2,x3..]中 x1,x3检测出来,如果发生错误则返回[]
sample:parse p "abcdef"
[(('a','c'),"def")] --检测出结果 为Parser (Char,Char)
parse p "ab"
[] --有误
3.选择
(+++)::Parser a->Parser a->Parser a
p +++ q = \inp -> case parse p inp of
[] -> parse q inp
[(v,out)]->[(v,out)]
这个是如果p Parser成功的话就返回p Parser的结果否则返回q Parser的结果.有点类似于 ?:表达式
4.派森原语 (derived primitives)
sat ::(Char->Bool)->Parser Char
sat p = do x<- item
if p x then return x else failture
主要是获取一次字符并测试.
可以通过对一些常用的char 类型检测 如isDigit之类的需要提前导入 Data.Char包
digit ::Parser Char
digit = sat isDigit
letter ::Parser Char
letter = sat isAlpha
char ::Char -> Parser Char
char x = sat (==x)
...
many ::Parser a->Parser [a]
many p = many1 p +++ return []
many1 ::Parser a -> [a]
many1 p = do v<-p
vs<- many p
return (v:vs)
many 和 many1类似与正则表达式中的?和+p来测试序列直到测试失败为止.
many允许失败 但是many1不允许失败
many 和 many1可以进行获取一段String中前面指定的格式如
parse (many digit) "123abc" -- [("123","abc")]
ident::Parser String
ident = do x<- lower;xs<- many alphaunm return (x:xs) --Haskell中的标识符开始字母是小写的
space ::Parse
space = do many (sat isSpace) return () --吞掉中间的空格
Sample :parse ident "abc def"
["abc"," def"]
第二次检测前就可以先使用space讲def前的" "吞掉
string ::String ->Parser String
string [] = return []
string (x:xs) = do char x
string xs
return (x:xs)
(这个不太懂)虽然例子简单 parse (string "abc") "abcdef" = [("abc","def")]
5.Handling spacing 不知道怎么翻译
token ::Parser a->Parser a
token p = do space
v<- p
space
return v
这边才到了词法分析(o(︶︿︶)o 真多)
identifier ::Parse String
identifier = token ident
natural ::Parse Int
natural = token nat
symbol ::String Parser String
symbol xs = token (string xs) //这边才用了string 就是用来测试标识符的
如 p::Parser [Int]
p = do symbol "["
n<- natural
ns <- many (do symbol ","
natural)
symbol "]"
return (n:ns)
p是用来检测如[1,2,3]的列表的 [] 或者错误的 列表都会定义为错
还有一些,现在的基本工具只能做到词法分析,语法分析下次再写 睡觉先ZZzz.