module Main where
import System.Environment
main :: IO ()
main = do
args <- getArgs
putStrLn $ "Hello," ++ args !! 0
()
unit type
这种类型只有一个值就是()
IO
类型是Monad
的一个实例
创建一个IO Action
Lift
一个普通值到IO monad
中
组合两个已有的IO Action
,形成一个新的
do block
不能在同一个do-block中混用不同的monad类型
Monad
是一个concept
有额外信息贴在这个值上
Monadic value
IO ()
中的()
就是
大部分函数不用关注这些额外信息
exercises:
main :: IO ()
main = do
args <- getArgs
putStrLn $ "Hello," ++ args !! 0 ++ "," ++ args !! 1
putStrLn $ show $ (read (args !! 0)) * (read (args !! 1))
line <- getLine
putStrLn $ "Hello," ++ line
import Text.ParserCombinators.Parsec
import System.Environment
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:" ++ show val
main :: IO ()
main = do
(expr:_) <- getArgs
putStrLn $ readExpr expr
Parsec
cabal install parsec
Parser
symbol
定义
一个monad,其中额外信息有
input stream中的位置
backtracking记录
fisrt&follow集
parse
parse :: Stream s Identity t => Parsec s () a -> SourceName -> s -> Either ParseError a
Either
类型
data Either a b = Left a | Right b deriving (Eq, Ord, Read, Show)
case ... of
模式匹配
_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:" ++ show val
增加对空字符的识别跳过.
>>
bind(不带值)
Attempt to match the first parser, then attempt to match the second with the remaining input, and fail if either fails.
data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
| Number Integer
| String String
| Bool Bool
parseString :: Parser LispVal
parseString = do
char '"'
x <- many (noneOf "\"")
char '"'
return $ String x
parseAtom :: Parser LispVal
parseAtom = do
first <- letter <|> symbol
rest <- many (letter <|> digit <|> symbol)
let atom = first: rest
return $ case atom of
"#t" -> Bool True
"#f" -> Bool False
_ -> Atom atom
parseNumber :: Parser LispVal
parseNumber = liftM (Number . read) $ many1 digit
parseExpr :: Parser LispVal
parseExpr = parseAtom
<|> parseString
<|> parseNumber
抽象数据类型
parseString
$
改变结合顺序
return
lift前面many
拿到的值进入到Parser monad中
parseAtom
<|>
, choice operator(一个combinator)
尝试第一个parser,如果失败尝试下一个
一个parser一定是在它消费输入前失败掉, 但是它需要看输入才能判断是否失败, 因此需要backtrack.
:
, list cons operator
parseNumber
从右向左读,函数都是右结合的
many1 digit
返回的是Parser String
, 没有办法只是应用(Number . read)
liftM
将函数应用到monad中的值里,