Проблема при смешивании классов типов и семейств типов - PullRequest
9 голосов
/ 07 апреля 2010

Этот код прекрасно компилируется:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
  UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables,
  TypeOperators, TypeSynonymInstances, TypeFamilies #-}
class Sel a s b where
  type Res a s b :: *

instance Sel a s b where
  type Res a s b = (s -> (b,s))

instance Sel a s (b->(c,a)) where
  type Res a s (b->(c,a)) = (b -> s -> (c,s))

но как только я добавлю предикат R, ghc не будет работать:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
  UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables,
  TypeOperators, TypeSynonymInstances, TypeFamilies #-}
class Sel a s b where
  type Res a s b :: *

instance Sel a s b where
  type Res a s b = (s -> (b,s))

class R a where
  type Rec a :: *
  cons :: a -> Rec a
  elim :: Rec a -> a
instance Sel a s (b->(c,Rec a)) where
  type Res a s (b->(c,Rec a)) = (b -> s -> (c,s))

жалуется, что:

    Illegal type synonym family application in instance:
        b -> (c, Rec a)
    In the instance declaration for `Sel a s (b -> (c, Rec a))'

что это значит и (самое главное) как это исправить?

Спасибо

Ответы [ 3 ]

12 голосов
/ 07 апреля 2010

Типы семейств односторонние: вы можете расширить Rec a до его вычисляемого типа, но вы не можете (уникально) перейти от расширения обратно к Rec a.Это делает приложения функций типа неподходящими для сигнатур экземпляров, поскольку они никогда не могут инициировать применение экземпляра.

Вместо этого вы можете попробовать:

instance Rec a ~ reca => Sel a s (b->(c,reca))

Это означает что-то другое: оно говорит любую функциюb -> (c, reca) является экземпляром, а затем, когда он безвозвратно сопоставлен, компилятор проверяет, что Rec a ~ reca.Но это может быть достаточно, чтобы хотеть в вашем случае.

1 голос
/ 07 апреля 2010

Это означает, что вам не разрешается использовать семейства синонимов типов при объявлении экземпляров типов. См. «Семейства типов и объявления экземпляров» руководства GHC.

Единственный способ исправить это - выполнить рефакторинг, чтобы он как-то не понадобился.

1 голос
/ 07 апреля 2010

Rec не является конструктором типов; это функция типа. Может быть, вы можете использовать его только в типе значения определения типа, а не в объявлении класса? Я дико догадываюсь здесь; Я не понимаю все правила для семейства типов.

Я не знаю, как это исправить, но некоторые вещи, которые нужно попробовать:

  • Избавьтесь от класса Sel и просто определите type family Res a s b :: *. Используйте type instance вместо механизма классов.

  • Едва ли возможно, что инъекция типа Rec с использованием data поможет, но я так не думаю.

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

...