Как далее ограничить существующий класс типов в Haskell - PullRequest
5 голосов
/ 07 марта 2012

Есть ли способ дополнительно ограничить контекст существующего класса типов?

Например, класс типа Functor:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

Это определение класса не обязывает a или b быть элементом Show. Также этот класс типов является классом, который включен мной сам, поэтому я не могу влиять на определение классов. Возможно ли позднее разрешить только те a и b, которые являются членами Show?

Ответы [ 2 ]

11 голосов
/ 07 марта 2012

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

Однако вы можете обернуть класс и добавить нужные ограничения:

class Functor f => ShowFunctor f where
    smap :: (Show a, Show b) => (a -> b) -> f a -> f b
    smap f = fmap f

и затем используйте этот класс вместо исходного.

Но, возможно, вам не нужен дополнительный класс, и для ваших приложений достаточно определить smap на верхнем уровне и просто использовать еговместо fmap,

smap :: (Functor f, Show a, Show b) => (a -> b) -> f a -> f b
smap = fmap
2 голосов
/ 07 марта 2012

Вы не можете сделать это, не ломая вещи (в настоящее время).

У вас есть несколько вариантов

  1. определить свой собственный ограниченный Functor класс
  2. небеспокоиться об определении класса и просто определить функцию, которая делает то, что вы хотите
  3. использовать пакет RMonad
  4. cheat

На самом деле, мытеперь знаете, как разрешить экземплярам добавлять ограничения, так что, возможно, однажды это будет не так уж плохо, см. Подкатегории в Haskell для статьи, которая почти точно решает эту проблему.Синтаксис в этой статье немного отличается от того, что в настоящее время работает в GHC, но в основном мы хотели бы переопределить класс Functor, чтобы он выглядел как

class Functor f where
   type SubCat f :: * -> Constraint -- associated constraint
   type SubCat f = () -- default definition
   fmap :: (SubCat f a, SubCat f b) => (a -> b) -> f a -> f b
...