Parsec3 траблы
Aug. 1st, 2008 07:04 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
3-й parsec, как известно, построен для работы с Data.ByteString, что должно неимоверно поднять скорость парсинга, по сравнению с обычным строковым.
На ICFPC
_adept_ категорически высказался против использования 3-его parsec-а. Аргументом была именно скорость его работы. В качестве теста был представлен несложный разбор 15М файла. Жуткий 3-й парсек тормозил со страшной силой, причём на ByteString (что обычных, что lazy) даже был медленнее строк.
Всё таки это неправильно. Я переписал простой разборщик (не Parsec!) строк на ByteString, скорость возрасла в два раза. Значит, дело не в кривых ByteString. Хотя не думаю, что тут можно сомневаться. Потом после специализации нескольких важных функций в Parsec он почти догнал второй, отставая менее, чем в два раза.
Основная причина, устранив которую мы резко поднимаем производительность - это замена для many, который возвращает [a], хотя чаще всего нам нужен поток символов. В нашем случае это ByteString.
Просто сделать не получилось, я написал
Причём специализации тут уже совершенно не нужны.
Добавил следующие правила
Но они работают только при явном наличии many (satisfy f) или many (satisfy p > s), если же у нас выражение many digit, где digit сам является satisfy isDigit > "digit", то правило не срабатывает.
Т.е.
Ставлю digit INLINE - по барабану.
Как то можно заставить срабатывать правила на полученном после, скажем, INLINE кода?
На ICFPC
![[livejournal.com profile]](https://www.dreamwidth.org/img/external/lj-userinfo.gif)
Всё таки это неправильно. Я переписал простой разборщик (не Parsec!) строк на ByteString, скорость возрасла в два раза. Значит, дело не в кривых ByteString. Хотя не думаю, что тут можно сомневаться. Потом после специализации нескольких важных функций в Parsec он почти догнал второй, отставая менее, чем в два раза.
Основная причина, устранив которую мы резко поднимаем производительность - это замена для many, который возвращает [a], хотя чаще всего нам нужен поток символов. В нашем случае это ByteString.
Просто сделать не получилось, я написал
manyChars :: ... -> Parsec ... ByteString
Причём специализации тут уже совершенно не нужны.
Добавил следующие правила
{-# RULES "many/satisfy" forall p. many (satisfy p) = manyChars p #-} {-# RULES "many/satisfyErr" forall p s. many (satisfy p > s) = manyChars p > s #-}
Но они работают только при явном наличии many (satisfy f) или many (satisfy p > s), если же у нас выражение many digit, где digit сам является satisfy isDigit > "digit", то правило не срабатывает.
Т.е.
digit = satisfy isDigit > "digit" many digit -- не работает many (satisfy isDigit > "digit") -- работает
Ставлю digit INLINE - по барабану.
Как то можно заставить срабатывать правила на полученном после, скажем, INLINE кода?
no subject
Date: 2008-08-01 03:33 pm (UTC)При задании правил, по идее, можно указать этапы компиляции, на которых они будут срабатывать.
The "[2]" means that the rule is active in Phase 2 and subsequent phases. The inverse notation "[~2]" is also accepted, meaning that the rule is active up to, but not including, Phase 2.
http://www.haskell.org/ghc/docs/6.8.2/html/users_guide/rewrite-rules.html
no subject
Date: 2008-08-01 04:01 pm (UTC)no subject
Date: 2008-08-01 04:34 pm (UTC)no subject
Date: 2008-08-01 04:44 pm (UTC)no subject
Date: 2008-08-20 08:36 am (UTC)no subject
Date: 2008-08-20 09:01 am (UTC)Написал свой
{-# INLINE myDigit #-}
myDigit :: Parsec BS.ByteString () Char
myDigit = satisfy isDigit -- > "digit"
так инлайнится, а заменю () на u - нет. Имеется в виду тип
myDigit :: Parsec BS.ByteString u Char