Я понимаю вашу ситуацию, но вы обнаружите, что для изучения функционального программирования вам нужно будет адаптировать свою точку зрения к документации, которую вы найдете, а не наоборот. К счастью, в 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, где приложение из этих концепций в программировании родился.