Какую функциональность вы получаете бесплатно с помощью Functors или других классов типов?

Я прочитал статья, в которой говорилось:

Предоставление экземпляров для многих стандартных классов классов [Functors] немедленно даст вам много возможностей для практически бесплатного

Мой вопрос: что это за функциональность, которую вы получаете бесплатно (для функторов или других типов)? Я знаю, что такое определение функтора, но что я могу получить для free, определив что-то как функтор/другой тип-класс. Что-то другое, чем более красивый синтаксис. В идеале это были бы общие и полезные функции, которые работают с функторами/другими типами классов.

Мое воображение (может быть неправильным) о том, какие свободные средства являются функциями такого рода: TypeClass x => useful x y = ..

== Edit/Additition ==

Я предполагаю, что я в основном спрашиваю о более абстрактных типах (и ошеломляющих мозгах) типах, таких как этот образ. Для менее абстрактных классов, таких как Ord, моя объектно-ориентированная интуиция понимает.

Ответ 1

Функторы просты и, вероятно, не лучший пример. Давайте посмотрим на Монады:

  • liftM - если что-то есть Монада, это также Functor, где liftM - fmap.
  • >=>, <=<: вы можете бесплатно создавать функции a -> m b, где m - ваша монада.
  • foldM, mapM, filterM... вы получаете кучу полезных функций, которые обобщают существующие функции для использования вашей монады.
  • when, guard * и unless - вы также получаете некоторые функции управления бесплатно.
  • join - это на самом деле довольно фундаментально для определения монады, но вам не нужно определять его в Haskell, так как вы определили >>=.
  • трансформаторы - ErrorT и прочее. Вы можете запускать обработку ошибок на новый тип, бесплатно (дайте или возьмите)!

В принципе, вы получаете широкий набор стандартных функций, "поднятых", чтобы использовать свой новый тип, как только вы делаете его экземпляром Monad. Он также становится тривиальным (но, увы, не автоматическим), чтобы сделать его Functor и Applicative.

Однако, это все "симптомы" более общей идеи. Вы можете написать интересный, нетривиальный код, который применяется ко всем монадам. Вы могли бы найти некоторые из функций, которые вы написали для своего типа, которые полезны в вашем конкретном случае по любой причине, могут быть обобщены ко всем монадам. Теперь вы можете внезапно воспользоваться своей функцией и использовать ее для парсеров и списков, а также майбы и...

* Как сказал Даниэль Фишер, guard требует MonadPlus, а не Monad.

Ответ 2

Функторы не очень интересны сами по себе, но они являются необходимым шагом, чтобы попасть в аппликативные функторы и Traversables.

Основное свойство, которое делает полезными функторы полезными, состоит в том, что вы можете использовать fmap с аппликативным оператором <*> для "подъема" любой функции любой арности для работы с аппликативными значениями. То есть вы можете превратить любой a -> b -> c -> d в Applicative f => f a -> f b -> f c -> f d. Вы также можете взглянуть на Data.Traversable и Data.Foldable, которые содержат несколько функций общего назначения, которые включают аппликативные функторы.

Alternative - это специализированный прикладной функтор, который поддерживает выбор между альтернативами, которые могут "терпеть неудачу" (точное значение "пустого" зависит от аппликативный пример). Аппликативные синтаксические анализаторы являются одним из практических примеров, когда определения some и many очень интуитивно понятны (например, соответствуют некоторому шаблону нуль или больше раз или один или несколько раз).

Монады - один из самых интересных и полезных классов типов, но они уже хорошо освещены в других ответах.

Monoid - это еще один класс типа, который является простым и сразу же полезным. Он в основном определяет способ совместного использования двух частей данных, который затем дает общий concat, а также функциональность в вышеупомянутом модуле Foldable, а также позволяет использовать Writer монада с типом данных.

Ответ 3

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

В качестве примера реализация класса типа Ord позволит вам использовать такие вещи, как sort, min, max и т.д. В противном случае вам понадобится sortBy и т.п.

Ответ 4

Да, это означает, что реализация класса type Foo предоставляет вам все другие функции, которые имеют ограничение Foo "бесплатно.

Класс типа Functor не слишком интересен в этом отношении, поскольку он не дает вам многого.

Лучшим примером являются монады и функции в модуле Control.Monad. После того, как вы определили две функции Monad (>>=) и return для вашего типа, вы получите еще тридцать функций, которые затем могут использоваться для вашего типа.

Некоторые из наиболее полезных включают в себя: mapM, sequence, forever, join, foldM, filterM, replicateM, when, unless и liftM, Они все время отображаются в коде Haskell.

Ответ 5

Как говорили другие, сам Functor на самом деле не дает вам много свободного. В принципе, более высокий уровень или общий класс (это означает, что больше подходит этому описанию), то тем меньше "свободной" функциональности, которую вы получите. Так, например, Functor и Monoid не предоставляют вам много, но Monad и Arrow предоставляют вам множество полезных функций бесплатно.

В Haskell все-таки хорошая идея написать экземпляр для Functor и Monoid, хотя (если ваш тип данных действительно является функтором или моноидом), потому что мы почти всегда пытаемся использовать наиболее общий интерфейс при написании функций. Если вы пишете новую функцию, которая может уйти, только используя fmap для работы с вашим типом данных, тогда нет причин искусственно ограничивать эту функцию до Monad или Applicative s, так как это может быть полезно позже для других вещей.

Ответ 6

Ваша объектно-ориентированная интуиция переносится, если вы читаете "интерфейс и реализацию" для "typeclass и instance". Если вы сделаете свой новый тип C экземпляром стандартного типа B, то вы получите бесплатно, что ваш тип будет работать со всем существующим кодом A, который зависит от B.

UML diagram

Как говорили другие, когда тип класса похож на Monad, то бесплатными являются многие библиотечные функции, такие как foldM и when.