Problema ao misturar classes e famílias de tipos
-
25-09-2019 - |
Pergunta
Este código compila bem:
{-# 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))
Mas assim que eu adiciono o predicado do RHC falha:
{-# 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))
reclamando isso:
Illegal type synonym family application in instance:
b -> (c, Rec a)
In the instance declaration for `Sel a s (b -> (c, Rec a))'
O que isso significa e (o mais importante) como faço para consertar isso?
Obrigado
Solução
As famílias do tipo são unidirecionais: você pode expandir Rec a
para o seu tipo calculado, mas você não pode (exclusivamente) ir da expansão de volta para Rec a
. Isso torna as aplicações do tipo funções inadequadas, por exemplo, assinaturas, pois nunca podem acionar a instância a ser aplicada.
Você poderia tentar: em vez disso:
instance Rec a ~ reca => Sel a s (b->(c,reca))
Isso significa outra coisa: diz qualquer função b -> (c, reca)
é uma instância e, em seguida, quando ele corresponde irrevogavelmente, o compilador verifica que Rec a ~ reca
. Mas isso pode ser bom o suficiente para querer no seu caso.
Outras dicas
Rec
não é um construtor de tipo; É uma função de tipo. Talvez você possa usá -lo apenas no tipo de valor da definição de tipo, não em uma declaração de classe? Estou supondo muito aqui; Não entendo todas as regras para as famílias do tipo.
Não sei como consertar, mas algumas coisas para tentar incluir:
Livre -se da classe sel e apenas defina
type family Res a s b :: *
. Usartype instance
em vez do mecanismo de classe.É quase possível que fazer tipo
Rec
injetivo usandodata
vai ajudar, mas acho que não.Volte ao menor número de extensões de idiomas que possam funcionar - facilitará a ajuda de outras pessoas e também ajudará o compilador.
Isso significa que você não tem permissão para usar as famílias do tipo Synomym ao declarar instâncias de tipo. Veja a seção "Famílias do tipo e declarações de instância" do manual do GHC.
A única maneira de corrigi -lo é refatorar para não precisar de alguma forma.