Расширяемые классы типа Haskell

Я читаю статью о программировании с надписью и набираю следующую цитату:

"[...] в отличие от классов типа Haskell, тип данных [...] закрыт" в том смысле, что нельзя добавлять новые типы во вселенную без расширения тип данных.

Мой вопрос о новичке: в каком смысле классы типа Haskell open? Как они расширяемы? Кроме того, каковы теоретико-теоретические последствия наличия этого свойства (open vs closed)?

Спасибо!

Ответы

Ответ 1

Учитывая класс типа like:

class Monoid m where
    mempty  :: m
    mappend :: m -> m -> m

... он (в основном) реализован под капотом как тип словаря:

data Monoid m = Monoid
    { mempty  :: m
    , mappend :: m -> m -> m
    }

Экземпляры вроде:

instance Monoid [a] where
    mempty  = []
    mappend = (++)

... переводятся в словари:

listIsAMonoid :: Monoid [a]
listIsAMonoid = Monoid
    { mempty  = []
    , mappend = (++)
    }

... и компилятор справляется с этим словарем, когда вы используете списки в качестве Monoid s.

Это подводит нас к вашим вопросам:

В каком смысле открываются классы классов Haskell? Как они расширяемы?

Они открыты в том же смысле, что и полиморфные значения открыты. У нас есть несколько типов полиморфных данных:

data Monoid m = ...

... и мы можем создать экземпляр полиморфной переменной типа m для любого типа, где мы можем предоставить подходящие значения для полей mempty и mappend.

Ответ 2

Классы классов открыты, потому что вы можете сделать произвольный тип экземпляром. Когда вы создаете класс типа, вы указываете интерфейс, но не типы, которые принадлежат ему. Затем в любом коде, который включает определение typeclass, вы можете сделать свой экземпляр своего типа, предоставляя необходимые функции из интерфейса, используя синтаксис instance TypeClass type of.

Ответ 3

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

Ключевым моментом является то, что я могу написать код, который работает с значениями с некоторым ограничением типа-типа, и тот же код без каких-либо изменений может использоваться для типов, которые не существовали, когда я писал класс типа.

Конкретные типы данных в Haskell "закрыты" тем, что этого не может быть. Если я пишу код, который работает с членами определенного типа данных (даже если он является полиморфным), то вы не можете использовать этот код для работы над новыми видами вещей, о которых я не думал, если вы не можете изменить тип (который, вероятно, требует изменения всех мест, где он используется).