Во-первых, давайте посмотрим на новый тип парсера без синтаксиса записи:
newtype Parser' a = Parser' (String -> Maybe (a,String))
Должно быть очевидно, что делает этот тип: он хранит функцию String -> Maybe (a,String)
. Чтобы запустить этот парсер, нам нужно будет создать новую функцию:
runParser' :: Parser' -> String -> Maybe (a,String)
runParser' (Parser' p) i = p i
И теперь мы можем запускать парсеры вроде runParser' (Parser' $ \s -> Nothing) "my input"
.
Но теперь обратите внимание, что, поскольку функции Haskell каррированы, мы можем просто удалить ссылку на ввод i
, чтобы получить:
runParser'' :: Parser' -> (String -> Maybe (a,String))
runParser'' (Parser' p) = p
Эта функция в точности эквивалентна runParser'
, но вы можете подумать об этом по-другому: вместо того, чтобы явно применять функцию анализатора к значению, она просто берет анализатор и извлекает из него функцию анализатора; однако благодаря каррированию runParser''
по-прежнему можно использовать с двумя аргументами.
Теперь вернемся к исходному типу:
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
Единственная разница между вашим типом и моим заключается в том, что ваш тип использует синтаксис записи, хотя это может быть немного сложно распознать, поскольку newtype
может иметь только одно поле; этот синтаксис записи автоматически определяет функцию parse :: Parser a -> (String -> Maybe (a,String))
, которая извлекает функцию String -> Maybe (a,String)
из файла Parser a
. Надеюсь, остальное должно быть очевидно: благодаря каррированию parse
можно использовать с двумя аргументами, а не с одним, и это просто приводит к запуску функции, хранящейся в Parser a
. Другими словами, ваше определение точно эквивалентно следующему коду:
newtype Parser a = Parser (String -> Maybe (a,String))
parse :: Parser a -> (String -> Maybe (a,String))
parse (Parser p) = p
person
bradrn
schedule
19.02.2020