Почему GHC не анализирует экземпляр функтора для 'data Wrap fa = Wrap (fa)'? - PullRequest
0 голосов
/ 09 апреля 2019

В Программирование на Haskell из первых принципов раздел 16.13, тип данных Wrap представлен для демонстрации типа, экземпляр Functor которого требует ограничения класса типов для одного из его параметров:

data Wrap f a =
  Wrap (f a)
  deriving (Eq, Show)

После демонстрации нескольких неправильных экземпляров Functor для (Wrap f) отображается правильный экземпляр:

instance Functor f => Functor (Wrap f) where
  fmap g (Wrap fa) = Wrap (fmap g fa)

То, что этот экземпляр класса типов должен работать, мне кажется правильным. Действительно, GHC принимает это без жалоб.

Чтобы убедить себя в том, что требуется ограничение 'Functor f', я попытался создать свой собственный экземпляр класса типов без него. Мой подход фокусируется на сопоставлении с образцом, чтобы использовать f в "functor-ish" без fmap, подобно подходам, показанным ранее в книге. Вот попытка:

instance Functor (Wrap f) where
  fmap g (Wrap (f a)) = Wrap f (g a)

Когда я загружаю это в GHCi, я получаю следующую ошибку:

Prelude> :l 16.12-wrap.hs
[1 of 1] Compiling Main             ( 16.12-wrap.hs, interpreted )

16.12-wrap.hs:10:17: error: Parse error in pattern: f
   |
10 |   fmap g (Wrap (f a)) = Wrap f (g a)
   |                 ^^^
Failed, no modules loaded.

Может кто-нибудь объяснить проблему с моим покушением? Мне кажется, что GHC имеет достаточно информации, чтобы сделать вывод, что f имеет вид (* -> *) из определения Wrap сверху, поэтому я не могу понять, почему моя попытка не анализируется.

1 Ответ

3 голосов
/ 09 апреля 2019

fmap g (Wrap (f a)) в левой части определения приводит к ошибке разбора, потому что (f a) не является синтаксически допустимым шаблоном.

Мой подход фокусируется на сопоставлении с образцом, чтобы использовать f в "functor-ish" без fmap [...]

Если не учитывать синтаксис, вы не можете буквально использовать это f в качестве шаблона таким образом. f в объявлении экземпляра является конструктором типа, в то время как шаблоны предназначены для сопоставления конструкторам значений и значений. Для минимальной иллюстрации, в ...

id :: x -> x
id x = x

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

Если бы я хорошо понял ваше намерение, планировалось использовать (f a) в качестве шаблона, так чтобы f соответствовал любому конструктору "functor-ish" с чем-то (a) внутри. Это не сработает (мы не можем абстрагироваться над конструкторами таким образом), но даже если это сработает, этого будет недостаточно для этой задачи. Это связано с тем, что не все функторные значения соответствуют форме конструктора, заключающего в себе другое значение. Один пример: Nothing :: Maybe Integer. Здесь нет ни унарного конструктора значений, ни каких-либо значений, которые будут переноситься.

...