Я следую за Gentle introduction to Haskell учебником, и представленный там код кажется сломанным. Мне нужно понять, так ли это, или мое понимание концепции неверно.Parse string with lex in Haskell
Я реализую анализатор для пользовательского типа: функция
data Tree a = Leaf a | Branch (Tree a) (Tree a)
печати для удобства
showsTree :: Show a => Tree a -> String -> String
showsTree (Leaf x) = shows x
showsTree (Branch l r) = ('<':) . showsTree l . ('|':) . showsTree r . ('>':)
instance Show a => Show (Tree a) where
showsPrec _ x = showsTree x
этот анализатор хорошо, но перерывы, когда есть пространства
readsTree :: (Read a) => String -> [(Tree a, String)]
readsTree ('<':s) = [(Branch l r, u) | (l, '|':t) <- readsTree s,
(r, '>':u) <- readsTree t ]
readsTree s = [(Leaf x, t) | (x,t) <- reads s]
это один считается лучшим soluti , но это не работает без пространств
readsTree_lex :: (Read a) => String -> [(Tree a, String)]
readsTree_lex s = [(Branch l r, x) | ("<", t) <- lex s,
(l, u) <- readsTree_lex t,
("|", v) <- lex u,
(r, w) <- readsTree_lex v,
(">", x) <- lex w ]
++
[(Leaf x, t) | (x, t) <- reads s ]
рядом я выбираю один из парсеров для использования с read
instance Read a => Read (Tree a) where
readsPrec _ s = readsTree s
тогда я загрузить его в GHCI, используя режим отладки Leksah (это unrelevant, я думаю), и попытаться разобрать две строки:
read "<1|<2|3>>" :: Tree Int -- succeeds with readsTree
read "<1| <2|3> >" :: Tree Int -- succeeds with readsTree_lex
когда lex
сталкивается |<2...
пар t прежней струны, он разбивается на ("|<", _)
. Это не соответствует части анализатора и не удается завершить разбор.
Есть два вопроса, возникающие в связи:
- Как определить синтаксический анализатор, который действительно игнорирует пространства, не требует их?
- как я могу определить правила для расщепления встречаются литералов с Лексом
Говоря о втором вопросе - спрашивается больше любопытства, как определение моего собственного лексера кажется более правильным, чем определение правил существующего.
, что было что-то я не был уверен. Я до сих пор не понимаю, почему это пример в книге. Возможно, реализация lex изменилась за последнее десятилетие. – sukhmel
Он говорит, что это следует за лексическими правилами Haskell, возможно, они предполагали, что вы не дадите ему '' <3|<4,5>> "на том основании, что для Haskell потребуется пространство между' '' и '<', чтобы отличить от потенциального '| <'. В тексте следует толковать очень подробно, но я согласен. –
Я нашел ответ на эту (по-видимому) внутреннюю кодовую базу для этой книги. Эта кодовая база не была включена в мою (переведенную) версию, что заставило меня не замечать это раньше. Спасибо за ваши усилия. – sukhmel