Pull to refresh

Comments 10

Велосипедненько.


А что, если в CSV будут дополнительные поля (или поля будут не по порядку)? Придётся менять код?
Экранирования в строках, кажется, нет (но несложно добавить).
.toInt будет бросать исключение, если что не так. Не вижу, чтобы оно обрабатывалось.


Почему бы не использовать Scala Parsers (правда эта библиотека небыстрая)?


"Очевидный подход" как-то нагляднее и наверняка быстрее.

Я согласен с вашими тезисами.

1. Придется, пришлось бы в любом случае, пока у нас парсер не обладает своим разумом.
2. Экранирования нет, и я написал почему. Акцент статьи на понимании того, куда можно вкрутить монаду, при желании. Не хотелось нагружать примеры логикой, к этому не относящейся.
3. Parser-combinators — тоже самое, статья не именно о том как парсить CSV.

Еще есть вариант разбивать строку по полям с помощью OpenCSV и потом работать не со строкой на входе, а со списком строк, тогда код из статьи будет применим с минимальными корректировками, но изобретать эскейпинг не придется.
Придется, пришлось бы в любом случае, пока у нас парсер не обладает своим разумом.

Это не так сложно. Я просто добавлял первой строкой в CSV-подобном формате названия полей, и потом с помощью таблицы "имя->индекс столбца" искал нужные столбцы, из которых брал данные.

Хм, тогда соглашусь.

Но тут тоже можно выкрутиться монадическим парсером, если сначала токенизировать в мапу по именам полей с помощью Parser[Map[String, String], String], а потом использовать мапу как остаток и парсить в сущность Parser[T, Map[String, String]]

Опять же, не знаю стал ли бы я так делать в продакшне)
Добавьте "Parser {case src =>" в листинг, это магическое слово, превращающее лямбду в частично примененную функцию. А то у меня мозг взорвался, прежде чем я понял код.
Да, это моя ошибка — я в процессе экспериментов избавился от PartialFunctions, но тут забыл заменить. Теперь исправил, на обычную функцию.

Спасибо за замечание)

Так вот почему у меня мозг взрывается от этого кода. Все дело в недостающем case!


Если серьезно, то у меня вопрос:
Я вот знаком со Скалой преимущественно по статьям на Хабре :). И для меня конструкции типа определения Parser в статье — вынос мозга каждый раз.
А вы правда привыкли к ней настолько, чтобы легко и непринужденно оперировать подобными сущностями?
Или все еще требуется значительное усилие, чтобы разобраться, что к чему?


Написать-то один раз можно (даже я, наверное, справлюсь — с n-ной попытки). Но потом же кто-то этот код регулярно читает.


Меня действительно этот вопрос интересует.

Ну если бы класс Parser был прост и интуитивен, я бы не написал об этом целую статью :)

На самом деле ответ на ваш вопрос есть в самой статье — не нужно любую задачу решать через монады.

Есть проблема в том, что скала достаточно богатый язык, чтобы в нем было очень легко прострелить себе ногу, но можно научиться брать эту его сторону под контроль и писать понятно.

В целом, в функциональном программировании есть свои паттерны (можно сказать что монада — один из них), и, научившись их распознавать, читать код становится намного проще. Тут похожая ситуация на ту, которая происходит, когда впервые изучаешь и пытаешься применять рекурсии. Как только мозг выворачивается в нужную сторону, все становится намного понятнее.

Писать на scala можно по-разному.


У меня процентов 90 scala-кода вообще императивно написано, только с добавлением функциональных .map(), .foreach() и т.п. Тяжёлую функциональщину приходится писать очень редко, да и в конце концов такой код воспринимается как несложный dsl (например, Scala Parsers).


Но от применения серьёзной функциональщины чаще отказываюсь из-за тормознутости (и временами дикой прожорливости) результата, а не из-за сложности написания/понимания.

Если вдруг кто-нибудь захочет писать аналогичный туториал, имеет смысл описать как раз переход от первого парсера к монадическому (в т.ч. соображения, почему и зачем надо так, а не иначе). Так как этот пример совсем неочевидный, тем более, что большая часть парсинга проходит через лямбду, вводимую в Parser.map, а не через лямбду из Parser.flatMap. И вообще, непонятно, зачем эти лямбды, отличающиеся только возвращаемым значением, введены дважды — только для удобства переопределения кастомных парсеров на основе строкового?
Sign up to leave a comment.

Articles