Функциональное программирование в реальном мире в Scala - PullRequest
35 голосов
/ 11 декабря 2011

Оооочень ...

Полугруппы, Моноиды, Монады, Функторы, Линзы, Катаморфизмы, Анаморфизмы, Стрелки ... Все это звучит хорошо, и после одного или двух упражнений (или десяти) вы можете понятьих суть.А с Scalaz вы получаете их бесплатно ...

Однако, с точки зрения программирования в реальном мире, я пытаюсь найти применение этим понятиям.Да, конечно, я всегда нахожу в Интернете кого-то, кто использует монады для ввода-вывода или линзы в Scala, но ... все же ...

Я пытаюсь найти что-то вроде "предписывающих" строкшаблон.Что-то вроде: «здесь вы пытаетесь решить это , и один хороший способ решить эту проблему - использовать линзы таким образом

Предложения?


Обновление: что-то в этом роде, с книгой или двумя, было бы замечательно (спасибо Полу): Примеры шаблонов проектирования GoF в основных библиотеках Java

Ответы [ 5 ]

19 голосов
/ 11 декабря 2011

Ключом к функциональному программированию является абстракция и сочетаемость абстракций. Монады, Стрелы, Линзы - все это абстракции, которые доказали свою полезность, главным образом потому, что они являются составными. Вы просили «предписывающий» ответ, но я собираюсь сказать нет. Возможно, вы не уверены, что функциональное программирование имеет значение ?

Я уверен, что многие люди в StackOverflow были бы более чем рады попытаться помочь вам решить специфическую проблему с помощью FP. Есть список вещей, и вы хотите просмотреть список и получить какой-то результат? Используйте сгиб. Хотите разобрать XML? hxt использует для этого стрелки. А монады? Ну, тонны типов данных оказываются монадами, поэтому изучите их, и вы откроете для себя множество способов манипулировать этими типами данных. Но трудно просто вытащить примеры из воздуха и сказать: «линзы - это правильный способ сделать это», «моноиды - лучший способ сделать это» и т. Д. Как бы вы объяснили новичку, в чем польза а для цикла есть? Если вы хотите [пусто], то используйте цикл for [таким образом]. Это так вообще; Есть множество способов использовать цикл for. То же самое относится и к этим абстракциям FP.

Если у вас многолетний опыт работы в ООП, не забывайте, что вы когда-то были новичком в ООП. Требуется время, чтобы изучить путь FP, и еще больше времени, чтобы выявить некоторые тенденции ООП. Дайте ему время, и вы найдете множество вариантов использования функционального подхода.

12 голосов
/ 11 декабря 2011

Я дал доклад в сентябре , посвященный практическому применению моноидов и аппликативных функторов / монад с помощью скалаза. Подтверждение . Я дал другую версию того же доклада в Scala Lift Off , где акцент был сделан больше на валидации. Я бы смотрел первый доклад до тех пор, пока не начну проверку, а затем переходил ко второму докладу (через 27 минут).

Существует также суть, которую я написал , которая показывает, как вы можете использовать Проверка в "практическом" приложении. То есть, если вы разрабатываете программное обеспечение для вышибалов ночного клуба.

7 голосов
/ 11 декабря 2011

Я думаю, что вы можете использовать обратный подход, и вместо этого, когда вы пишете небольшую часть функциональности, спросите себя, подходит ли какой-либо из них: полугруппы, моноиды, монады, функторы, линзы, катаморфизмы, анаморфизмы, стрелки ... многоиз этих концепций можно использовать локально.

Как только вы начнете идти по этому пути, вы можете увидеть использование повсюду.Для меня я получаю полугруппы, моноиды, монады, функторы.Итак, возьмем пример ответа на этот вопрос Как мне заполнить список объектов новыми значениями .Это реальное использование для человека, задающего вопрос (самописанный нуб).Я пытаюсь ответить простым способом, но я должен воздержаться от того, чтобы почесать зуд "здесь есть моноиды".

Теперь поцарапаем: используя foldMap и тот факт, что Int и List являются моноидами и что свойство monoid сохраняется при работе с кортежем, картами и параметрами:

// using scalaz
listVar.sliding(2).toList.foldMap{
  case List(prev, i) => Some(Map(i -> (1, Some(List(math.abs(i - prev))))))
  case List(i) => Some(Map(i -> (1, None)))
  case _ => None
}.map(_.mapValues{ case (count, gaps) => (count, gaps.map(_.min)) })

Но яне приходите к такому результату, думая, что Я буду использовать функциональное программирование на основе ядра .Это становится более естественным, если подумать , что кажется проще, если я сочиню эти моноиды в сочетании с тем фактом, что у скалаза есть служебные методы, такие как foldMap.Интересно, что при взгляде на полученный код не очевидно, что я полностью думаю о моноиде.

6 голосов
/ 11 декабря 2011

Вам может понравиться этот разговор Криса Маршалла.Он рассказывает о нескольких вкусностях Скалаза, а именно: Моноид и Валидация, со многими практическими примерами.Иттай Дрор написал очень доступный пост о том, как Functor, Applicative Functor и Monad могут быть полезны на практике. Eric Torreborre и В блогах Debasish Gosh также есть куча постов, посвященных случаям использования категориальных конструкций.

В этом ответе просто перечисляются несколько ссылок вместо предоставления некоторыхреальная субстанция здесь.(Лень писать.) Надеюсь, вы все равно найдете это полезным.

4 голосов
/ 19 декабря 2011

Я понимаю вашу ситуацию, но вы обнаружите, что для изучения функционального программирования вам нужно будет адаптировать свою точку зрения к документации, которую вы найдете, а не наоборот. К счастью, в Scala у вас есть возможность постепенно стать функциональным программистом.

Чтобы ответить на ваши вопросы и объяснить разницу в точке зрения, мне необходимо различать «классы типов» (моноиды, функторы, стрелки), математически называемые «структуры» и общие операции или алгоритмы (катаморфизмы или складки, анаморфизмы или разворачивается и т. д.). Эти два часто взаимодействуют, так как многие общие операции определены для определенных классов типов данных.

Вы ищете предписывающие ответы, похожие на шаблоны проектирования: когда применяется эта концепция? Правда в том, что вы наверняка видели предписывающие ответы, и они являются просто определениями различных понятий. Проблема (для вас) состоит в том, что эти ответы по своей сути отличаются от шаблонов проектирования, но это так по веским причинам.

С одной стороны, универсальные алгоритмы не являются шаблонами проектирования, которые предлагают структуру для кода, который вы пишете; это абстракции, определенные на языке, который вы можете применять напрямую. Они являются общими описаниями общих алгоритмов, которые вы уже реализуете сегодня, но от руки. Например, всякий раз, когда вы вычисляете максимальный элемент списка, сканируя его, вы жестко программируете складку; когда вы суммируете элементы, вы делаете то же самое; и так далее. Когда вы узнаете это, вы можете объявить суть выполняемой вами операции, вызвав соответствующую функцию свертывания. Таким образом, вы сохраняете код и ошибки (нет возможности для отдельных ошибок), и вы экономите читателю усилия на считывание всего необходимого кода.

С другой стороны, структуры касаются не цели, которую вы имеете в виду, а свойств объектов, которые вы моделируете. Они более полезны для построения программного обеспечения снизу вверх, чем сверху вниз: при определении ваших данных вы можете заявить, что это, например, моноид Позже, при обработке ваших данных, у вас есть возможность использовать операции, например, моноиды для реализации вашей обработки. В некоторых случаях полезно стремиться выразить ваш алгоритм в терминах предопределенных. Например, очень часто, если вам нужно уменьшить дерево до одного значения, фолд может выполнить большинство или все, что вам нужно. Конечно, вы также можете объявить, что ваш тип данных является моноидом, когда вам нужен универсальный алгоритм для моноидов; но чем раньше вы это заметите, тем раньше вы сможете снова использовать универсальные алгоритмы для моноидов.

Последний совет: вероятно, большая часть документации, которую вы найдете об этих концепциях, касается Haskell, потому что этот язык существует гораздо дольше и поддерживает их довольно элегантным способом. Здесь весьма рекомендуются Learn for Haskell for Great Good , курс Haskell для начинающих, где, среди прочего, главы с 11 по 14 посвящены некоторым классам типов, и Typeclassopedia (которая содержит ссылки на различные статьи с конкретными примерами). РЕДАКТИРОВАТЬ: Наконец, пример приложений Monoids, взятых из Typeclassopedia, здесь: http://apfelmus.nfshost.com/articles/monoid-fingertree.html. Я не говорю, что есть немного документации для Scala, просто есть больше в Haskell, и Haskell, где приложение из этих концепций в программировании родился.

...