Проблема при смешивании классов и семейств типа
-
25-09-2019 - |
Вопрос
Этот код компилируется нормально:
{-# 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.
Единственный способ, которым вы можете исправить это, - это рефактору так, чтобы ему не нужно как-то.