Проблема при смешивании классов и семейств типа

StackOverflow https://stackoverflow.com/questions/2590495

Вопрос

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

{-# 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))

Но как только добавит PREDICH 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))'

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

Спасибо

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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

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

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

Единственный способ, которым вы можете исправить это, - это рефактору так, чтобы ему не нужно как-то.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top