Estou tentando criar meu próprio tipo de dados, que fará parte da classe Monad, mas
newtype Container a = Container a deriving Monad
me dá este erro:
* Can't make a derived instance of `Monad Container'
(even with cunning GeneralizedNewtypeDeriving):
cannot eta-reduce the representation type enough
* In the newtype declaration for `Container'
|
30 | newtype Container a = Container a deriving Monad
Funciona bem para outras classes (Show, por exemplo), mas não para o Monad, então como convencer o ghci a instanciar minha classe Container to Monad?
obrigado
a
não é um exemplo de mônada, portanto, não faz muito sentido. Se você, por exemplo, usassenewtype Container a = Container [a] deriving (Functor, Applicative, Monad)
, funcionará, já que[]
é uma instância deMonad
.GenerlizedNewtypeDeriving
é especificamente para "elevar" as instâncias do tipo agrupado para o novo tipo. A questão de como (ou se) alguém pode derivar automaticamente umaMonad
instânciaContainer
ainda é interessante. (O fato debase
definir aMonad
instância paraIdentity
explícito sugere que você não pode.)Monad
não é uma das classes de tipo que o padrão Haskell disponibiliza para ser derivada automaticamente (Show
é, juntamente com algumas outras básicas). O GHC pode fazer isso com as extensões corretas, acredito.GeneralizedNewtypeDeriving
está ativada e uma pergunta é por que ainda não funciona.Respostas:
Somente um conjunto fixo de classes padrão suporta derivações prontas para uso:
Em particular
Monad
, não pertence a essa lista, nem a extendida.Existem mais extensões que generalizam a derivação de classes arbitrárias, mas elas não podem ser 100% automatizadas. Alguém em algum lugar precisa especificar como essa derivação deve ser feita; dependendo da classe, o usuário pode ser obrigado a carregar o fardo, porque há informações que fundamentalmente não podem ser inferidas.
No seu caso, o newtype
Container
é representacionalmente equivalente àIdentity
mônada na biblioteca padrão, para que você possa usarDerivingVia
:Há apenas uma instância sensata nessa situação muito específica, mas na maioria das vezes não é fácil dizer qual deve ser a instância, mesmo que exista apenas uma.
fonte
Functor
eApplicative
, mas depois comparar o tipo deContainer 3 >>= (+1)
comIdentity 3 >>= (+1)
. Não sei se isso está relacionadoDerivingVia
ou não.Container 3 >>= (+ 1) :: Num (Container b) => Container b
eIdentity 3 >>= (+ 1) :: Num b => Identity b
não sei por queContainer b
, ao invés dissob
, tem aNum
restrição.)(+ 1) :: Num c => c -> c
como uma flecha Kleisli,(+ 1) :: a -> Container b
você precisa se unificarc ~ Container b
. Mas não tenho certeza de qual é o seu ponto de partida.Identity
que não está definidoContainer
, comoIdentity 3 >>= (+1)
avalia aIdentity 4
.instance Num a => Num (Identity a)
definido.