Что именно делает "получение Functor"?
Я пытаюсь выяснить, какие именно правила для deriving Functor
в Haskell.
Я видел сообщения о сообщениях об этом, и я видел тестовый код об этом, но я не могу найти официальную документацию о том, что такое правила. Может кто-то прояснить и/или указать мне нужное место?
Ответы
Ответ 1
Чтобы использовать deriving Functor
, вы должны включить прагму языка DeriveFunctor
и применить ее к полиморфному типу с ковариантной переменной конечного типа - другими словами, тип, допускающий действительный экземпляр Functor
. Затем он получит "очевидный" экземпляр Functor
.
В прошлом была некоторая озабоченность тем, что производный экземпляр не так эффективен, как ручной кодированный, хотя я не могу найти этот материал.
Сам алгоритм был, насколько я мог найти, впервые предложенный Twan Van Laarhoven в 2007 году, и активно использует программирование Generic Haskell.
Ответ 2
Код, который фактически делает это дело, к сожалению, немного на волосатой стороне. Я считаю, что в основном потому, что раньше, более простой код иногда приводил к чрезмерному времени компиляции. Twan van Laarhoven придумал текущий код для решения этой проблемы.
Полученный экземпляр Functor
всегда делает очевидную вещь. Обычно это нормально, но иногда пропускает возможности. Например, предположим, что я пишу
data Pair a = Pair a a deriving Functor
data Digit a = One a | Two a a deriving Functor
data Queue a =
Empty
| Single a
| Deep !(Digit a) (Queue (Pair a)) !(Digit a) deriving Functor
Это сгенерирует (в GHC 8.2)
instance Functor Queue where
fmap ...
x <$ Empty = Empty
x <$ Single y = Single x
x <$ Deep pr m sf = Deep (x <$ pr) (fmap (x <$) m) (x <$ sf)
Можно лучше записать этот последний случай вручную:
x <$ Deep pr m sf = Deep (x <$ pr) (Pair x x <$ m) (x <$ sf)
Вы можете увидеть фактический производный код, используя -ddump-deriv
.