Haskell независимо решает вывести Bifunctor для моего типа данных?

По какой-то причине GHC, кажется, решает, что мой тип данных (с двумя параметрами типа) без всякой причины создает экземпляр Bifunctor.

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

{-# LANGUAGE FlexibleInstances #-}
module BifunctorError where

import Data.Bifunctor

instance Bifunctor f => Functor (f t) where
    fmap = bimap id

data Provenance p t = Provenance p t

-- Uncomment and try to compile: Overlapping instances ???
--instance Functor (Provenance p) where
--  fmap f (Provenance p x) = Provenance p (f x)

Я ожидал, что, поскольку я не предоставил ничего, что указывало бы на то, что Provenance создает экземпляр Bifunctor, этого не произойдет, и поэтому экземпляр Functor, производный от Bifunctor, не должен иметь значения. Это ошибка FlexibleInstances?


person Juan Casanova Jaquete    schedule 14.05.2019    source источник
comment
Это. Большое спасибо, я долго искал, но ничего не нашел. Мне потребовалось время, чтобы понять, в чем проблема. Могу я просто спросить, если вы знаете, почему Haskell не проверяет ограничения для определения потенциальных экземпляров? Это потому, что ограничения скорее передаются обратно в результирующий тип выражения? Что-то вроде: Отсутствие экземпляра Bifunctor Provenance не является доказательством того, что Provenance никогда не будет экземпляром Bifunctor, и поэтому могут быть перекрывающиеся экземпляры? Потому что проверка типов - это интуиционистская логика и т. Д.?   -  person Juan Casanova Jaquete    schedule 14.05.2019
comment
(1) Вот и все: отсутствие доказательств не является доказательством отсутствия. В частности, кто-то другой, использующий ваш код, может дать Provenance экземпляр Bifunctor, даже если вы об этом не узнаете. Классы Haskell работают в соответствии с предположением открытого мира. (2) См. Также этот очень хороший ответ, который я не добавил в список целей, потому что их слишком много происходит где-то в этом вопросе и ответе.   -  person duplode    schedule 14.05.2019


Ответы (1)


При поиске подходящего экземпляра класса типов GHC смотрит только на заголовок, но не на условия. Он соответствует условиям в качестве второстепенного шага. Поэтому, когда GHC ищет экземпляр Functor, все, что он видит, это

instance (Don't care) => Functor (f t) where
instance (Don't care) => Functor (Provenance p) where

И оба эти экземпляра идеально подходят. Бит (Don't care) вступит в игру позже. Итак, у вас есть несколько пересекающихся экземпляров, и это проблема.

Подробнее об этом можно узнать в этом вопросе. «Решение» - поиграть с расширением GHC OverlappingInstances, которое само по себе является чем-то вроде кроличьей норы.

person Silvio Mayolo    schedule 14.05.2019