Шаг 1: поиск + замена всех вхождений от Integer
до Double
. Теперь ваш синтаксический анализатор все еще может читать только целые числа, но внутренне он будет представлять их как Double
s.
Шаг 2: заставляет анализатор number
анализировать либо целое число, либо плавающее Точка первая. Целое число, которое вы уже записали: это просто последовательность цифр. Давайте переименуем его, чтобы лучше отразить то, что он делает:
parseInt :: CalcParser Double
parseInt = read <$> many1 digit
С плавающей точкой не намного сложнее: это последовательность цифр, за которой следует точка (точка), за которой следует другая последовательность цифр:
parseDouble :: CalcParser Double
parseDouble = do
whole <- many1 digit
char '.'
fract <- many1 digit
pure $ read $ whole <> "." <> fract
А затем любой номер будет просто "double или int":
number :: CalcParser Double
number = try parseDouble <|> parseInt
Еще две ноты:
Первый , обратите внимание, что сначала вы должны попробовать двойной. Если вы этого не сделаете, строка "8.32"
будет проанализирована как int, потому что префикс "8"
соответствует правилам для parseInt
.
Second , обратите внимание, что у вас есть использовать try
с parseDouble
. Если вы этого не сделаете, целые числа не будут проанализированы, потому что парсер parseDouble
будет использовать ввод до конца цифр, не увидит точку, потерпит неудачу, но не откатится до начало цифр , так что parseInt
не увидит никаких цифр и тоже потерпит неудачу. Комбинатор try
- это то, что выполняет откат к началу при сбое синтаксического анализатора.