Data.Attoparsec.Text
экспорт takeWhile
и takeWhile1
:Как я могу написать более общую (но эффективную) версию takeWhile1 attoparsec?
takeWhile :: (Char -> Bool) -> Parser Text
Потребляйте вход до тех пор, как предикат возвращает
True
и возвращает потребляемую вход.Этот анализатор не подведет. Он вернет пустую строку, если предикат возвращает
False
на первый символ ввода.[...]
takeWhile1 :: (Char -> Bool) -> Parser Text
Потребляйте вход до тех пор, как предикат возвращает
True
и возвращает потребляемый вход.Этот анализатор требует, чтобы предикат преуспел, по крайней мере, на одном символе ввода: он не сработает, если предикат никогда не вернет
True
или если в нем нет ввода.
attoparsec
«в документации рекомендует пользователь
Используйте
Text
-ориентированных Парсеров когда это возможно, например,takeWhile1
вместоmany1 anyChar
. Разница в производительности между двумя типами парсера составляет около 100 раз.
Тех парсеров очень полезен, но я продолжаю чувствовать потребность в более общую версию takeWhile1
, более конкретно, некоторого гипотетического анализатор
takeWhileLo :: (Char -> Bool) -> Int -> Parser Text
takeWhileLo f lo = undefined
что бы разобрать по крайней мереlo
символов, удовлетворяющим предикат f
, где lo
- произвольное неотрицательное целое число.
Я взглянул на takeWhile1
's implementation, но он использует кучу функций, закрытых для Data.Attoparsec.Text.Internal
, и не кажется легко обобщаемым.
я придумал следующую аппликативную реализация:
{-# LANGUAGE OverloadedStrings #-}
import Prelude hiding (takeWhile)
import Control.Applicative ((<*>))
import Data.Text (Text)
import qualified Data.Text as T
import Data.Attoparsec.Text
takeWhileLo :: (Char -> Bool) -> Int -> Parser Text
takeWhileLo f lo =
T.append . T.pack <$> count lo (satisfy f) <*> takeWhile f
Он работает как рекламируется,
λ> parseOnly (takeWhileLo (== 'a') 4) "aaa"
Left "not enough input"
λ> parseOnly (takeWhileLo (== 'a') 4) "aaaa"
Right "aaaa"
λ> parseOnly (takeWhileLo (== 'a') 4) "aaaaaaaaaaaaa"
Right "aaaaaaaaaaaaa"
но необходимость упаковки промежуточного списка результатов, возвращенного count
меня беспокоит, особенно для случаях, когда lo
является большим ... Похоже, что против этой рекомендации
использовать
Text
-ориентированная парсеры всякий раз, когда это возможно [...]
я упускаю что-то? Существует ли более эффективный/идиоматический способ реализации такого комбинатора takeWhileLo
?
Я полагаю, что я был слишком сосредоточен на внедрении 'takeWhileLo' в качестве аппликативного комбинатора. Ваше предложение имеет смысл. Благодарю. – Jubobs
Вы имели в виду 'mempty' вместо' empty'? – Jubobs
Это также работает. У нас есть экземпляры «Monoid», «Alternative» и «MonadPlus» для 'Parser' и' mempty', 'empty' и' mzero' все выраженные сбои. –