проверка на неоднозначность и отказы условий либерального покрытия для кода, работающего под GHC 7.6

У меня был умный механизм уровня типов, который работал на GHC 7.6, но не на более поздних версиях. Оглядываясь назад, я не совсем уверен, почему это когда-либо работало, но, тем не менее, я хотел бы как-то вернуть эту функциональность:

{-# LANGUAGE 
    PolyKinds 
  , FunctionalDependencies , FlexibleInstances , FlexibleContexts
  , OverlappingInstances
  , ScopedTypeVariables
  , TypeFamilies
  , UndecidableInstances
 #-}
module M where

import Data.Proxy

-- | A relation between a (maybe-partially-applied) type and that type fully
-- applied.
class Applied t (tab :: *) | t -> tab where
    -- | Fully apply a type @t@ with polymorphic arguments, yielding @tab@.
    applied :: Proxy t -> Proxy tab

instance Applied (t a) tab=> Applied t tab where
    applied _ = applied (Proxy :: Proxy (t a))

instance t ~ tab=> Applied t tab where -- always matches when `t` is kind `*`
    applied _ = Proxy :: Proxy tab

Это зависит от библиотеки tagged в GHC 7.6. Мы можем использовать его как:

$ ghci-7.6.3
Prelude> :l M.hs
[1 of 1] Compiling M                ( M.hs, interpreted )
Ok, modules loaded: M.
*M> 
*M> :t applied (Proxy :: Proxy Either)
applied (Proxy :: Proxy Either) :: Proxy (Either a a1)
*M> (return $ Right 'a') == applied (Proxy :: Proxy Either)
True

Однако это не компилируется по крайней мере на GHC 7.8.3 или более поздней версии:

$ ghci-7.8.3
GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :l M.hs
[1 of 1] Compiling M                ( M.hs, interpreted )

M.hs:19:10:
    Could not deduce (Applied (t a0) tab)
      arising from the ambiguity check for an instance declaration
    from the context (Applied (t a) tab)
      bound by an instance declaration:
                 Applied (t a) tab => Applied t tab
      at M.hs:19:10-42
    The type variable ‘a0’ is ambiguous
    In the ambiguity check for:
      forall (k :: BOX) (k1 :: BOX) (t :: k1 -> k) tab (a :: k1).
      Applied (t a) tab =>
      Applied t tab
    To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
    In the instance declaration for ‘Applied t tab’

M.hs:19:10:
    Illegal instance declaration for ‘Applied t tab’
      The liberal coverage condition fails in class ‘Applied’
        for functional dependency: ‘t -> tab’
      Reason: lhs type ‘t’ does not determine rhs type ‘tab’
    In the instance declaration for ‘Applied t tab’
Failed, modules load

Я думаю, что ответ здесь связан, но я пока не понимаю этого предложения.

Возможно, я мог бы обойти это. Единственное место, где я использую этот класс, — это подпись вида:

instance (Foo tab, Applied t tab)=> Bar (Proxy t) where

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


person jberryman    schedule 08.01.2015    source источник
comment
Это была просто ошибка, что 7.6 когда-либо принимал это. См. обсуждение на 8634, которое указывает на 1241, 2247 и 8356 для уточнения. Чтобы сказать, что вы можете сделать вместо этого, нам, вероятно, потребуется немного больше контекста о том, чего вы пытаетесь достичь.   -  person Daniel Wagner    schedule 09.01.2015
comment
Если я правильно понимаю, вы хотите утверждать для некоторого t :: * ^ n -> *, что существует экземпляр Foo (t a_1 a_2 .. a_n), где a_i — переменные разных типов. В этом случае вы можете заменить Applied (t a) tab на Applied (t X) tab, где X — любой тип. Пока X определен в вашем модуле и не экспортирован, никто не может создать экземпляр с этим типом, поэтому любой экземпляр, который унифицируется с X, должен быть задан с переменной типа.   -  person user2407038    schedule 09.01.2015


Ответы (1)


Ваш пример ghci работает для меня в ghc-7.8.3, если я избавлюсь от FD и включу -XAllowAmbiguousTypes. Это расширение потребует, чтобы вы аннотировали (используя ScopedTypeVariables) тип этой функции applied, когда она используется в instance (Foo tab, Applied t tab)=> Bar (Proxy t).

person aavogt    schedule 10.01.2015