Parsing 如何判断Parsec解析器是否在Haskell中使用常量堆空间
在一次采访中,我问了以下问题 解析器: 这是一个显著的进步,但我不明白为什么Parsing 如何判断Parsec解析器是否在Haskell中使用常量堆空间,parsing,haskell,heap-memory,tail-recursion,parsec,Parsing,Haskell,Heap Memory,Tail Recursion,Parsec,在一次采访中,我问了以下问题 解析器: 这是一个显著的进步,但我不明白为什么 manyllengthcontheap使用常量堆空间,而我原来的manyllength不使用 如果将()内联到多个长度的,它看起来有点像这样: manyLengthInline :: forall s u m a. Monad m => ParsecT s u m a -> ParsecT s u m Int manyLengthInline p = go 0 where go :: Int
manyllengthcontheap
使用常量堆空间,而我原来的manyllength
不使用
如果将()
内联到多个长度的,它看起来有点像这样:
manyLengthInline
:: forall s u m a. Monad m => ParsecT s u m a -> ParsecT s u m Int
manyLengthInline p = go 0
where
go :: Int -> ParsecT s u m Int
go !i =
ParsecT $ \s cok cerr eok eerr ->
let meerr :: ParserError -> m b
meerr err =
let neok :: Int -> State s u -> ParserError -> m b
neok y s' err' = eok y s' (mergeError err err')
neerr :: ParserError -> m b
neerr err' = eerr $ mergeError err err'
in unParser (pure i) s cok cerr neok neerr
in unParser (p *> go (i + 1)) s cok cerr eok meerr
manyLengthConstantHeapInline
:: forall s u m a. Monad m => ParsecT s u m a -> ParsecT s u m Int
manyLengthConstantHeapInline p = go 0
where
go :: Int -> ParsecT s u m Int
go !i =
ParsecT $ \s cok cerr eok eerr ->
let mcok :: Bool -> State s u -> ParserError -> m b
mcok success s' err =
let peok :: Int -> State s u -> ParserError -> m b
peok int s'' err' = cok int s'' (mergeError err err')
peerr :: ParserError -> m b
peerr err' = cerr (mergeError err err')
in unParser
(if success then go (i + 1) else pure i)
s'
cok
cerr
peok
peerr
meok :: Bool -> State s u -> ParserError -> m b
meok success s' err =
let peok :: Int -> State s u -> ParserError -> m b
peok int s'' err' = eok int s'' (mergeError err err')
peerr :: ParserError -> m b
peerr err' = eerr (mergeError err err')
in unParser
(if success then go (i + 1) else pure i)
s'
cok
pcerr
peok
peerr
in unParser ((p *> pure True) <|> pure False) s mcok cerr meok eerr
如果将(>>=)
内联到多个长度常量映射中,它看起来有点像这样:
manyLengthInline
:: forall s u m a. Monad m => ParsecT s u m a -> ParsecT s u m Int
manyLengthInline p = go 0
where
go :: Int -> ParsecT s u m Int
go !i =
ParsecT $ \s cok cerr eok eerr ->
let meerr :: ParserError -> m b
meerr err =
let neok :: Int -> State s u -> ParserError -> m b
neok y s' err' = eok y s' (mergeError err err')
neerr :: ParserError -> m b
neerr err' = eerr $ mergeError err err'
in unParser (pure i) s cok cerr neok neerr
in unParser (p *> go (i + 1)) s cok cerr eok meerr
manyLengthConstantHeapInline
:: forall s u m a. Monad m => ParsecT s u m a -> ParsecT s u m Int
manyLengthConstantHeapInline p = go 0
where
go :: Int -> ParsecT s u m Int
go !i =
ParsecT $ \s cok cerr eok eerr ->
let mcok :: Bool -> State s u -> ParserError -> m b
mcok success s' err =
let peok :: Int -> State s u -> ParserError -> m b
peok int s'' err' = cok int s'' (mergeError err err')
peerr :: ParserError -> m b
peerr err' = cerr (mergeError err err')
in unParser
(if success then go (i + 1) else pure i)
s'
cok
cerr
peok
peerr
meok :: Bool -> State s u -> ParserError -> m b
meok success s' err =
let peok :: Int -> State s u -> ParserError -> m b
peok int s'' err' = eok int s'' (mergeError err err')
peerr :: ParserError -> m b
peerr err' = eerr (mergeError err err')
in unParser
(if success then go (i + 1) else pure i)
s'
cok
pcerr
peok
peerr
in unParser ((p *> pure True) <|> pure False) s mcok cerr meok eerr
为什么manylengthConstantTheap
在堆空间不变的情况下运行,而
manyllength
没有?它看起来不像是对go
的递归调用
manyllength>ap
或manyllength
的尾部调用位置
将来编写parsec解析器时,我如何知道空间
对给定解析器的需求?李耀霞怎么知道的
manylengconstant地图
可以吗
我觉得我对预测哪些解析器将使用
一个大的输入上有很多内存
有没有一种简单的方法来确定给定的函数是否
Haskell中的tail递归而不运行它?或者更好,不用编译
它?尾部递归对于haskell代码在常量空间中运行来说不是必要的或足够的。@Carl这很有趣,谢谢。你能添加一个解释它的答案吗?或者给我指一篇文章或博客来解释它?
newtype ParsecT s u m a = ParsecT
{ unParser
:: forall b .
State s u
-> (a -> State s u -> ParseError -> m b) -- consumed ok
-> (ParseError -> m b) -- consumed err
-> (a -> State s u -> ParseError -> m b) -- empty ok
-> (ParseError -> m b) -- empty err
-> m b
}