Haskell - Automatische Monadeninstanz

8

Ich versuche, meinen eigenen Datentyp zu erstellen, der Teil der Monad-Klasse sein wird, aber

newtype Container a = Container a deriving Monad

gibt mir diesen Fehler:

   * 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

Es funktioniert gut für andere Klassen (z. B. Show), aber nicht für Monad. Wie kann ich ghci davon überzeugen, meine Container to Monad-Klasse zu instanziieren?

Vielen Dank

Edward Gray
quelle
1
Das Problem ist, dass aes sich nicht um eine Monade handelt, daher macht es nicht viel Sinn. Wenn Sie zum Beispiel verwenden würden, wird newtype Container a = Container [a] deriving (Functor, Applicative, Monad)es funktionieren, da []es sich um eine Instanz von handelt Monad.
Willem Van Onsem
2
GenerlizedNewtypeDerivingdient speziell zum "Anheben" der Instanzen des umschlossenen Typs auf den neuen Typ. Die Frage, wie (oder ob) man automatisch eine MonadInstanz ableiten kann, Containerist immer noch interessant. (Die Tatsache, dass basedie MonadInstanz Identityexplizit definiert wird, deutet darauf hin, dass dies nicht möglich ist.)
chepner
Monadgehört nicht zu den Typklassen, die der Haskell-Standard zur automatischen Ableitung bereitstellt ( Showzusammen mit einigen anderen grundlegenden). GHC kann es allerdings mit den richtigen Erweiterungen tun, glaube ich.
Robin Zigmond
@RobinZigmond Beachten Sie, dass die Meldung angibt GeneralizedNewtypeDeriving, dass sie aktiviert ist, und eine Frage ist, warum sie immer noch nicht funktioniert.
Alexey Romanov

Antworten:

9

Es funktioniert gut für andere Klassen (Show zum Beispiel)

Nur ein fester Satz von Standardklassen unterstützt das sofortige Ableiten:

In Haskell 98 sind die einzigen ableitbaren Klassen Gl., Ord, Enum, Ix, Bounded, Read und Show. Verschiedene Spracherweiterungen erweitern diese Liste.

--- Das GHC-Benutzerhandbuch

Insbesondere Monadgehört weder zu dieser noch zu der erweiterten Liste.

Es gibt weitere Erweiterungen, die das Ableiten auf beliebige Klassen verallgemeinern, die jedoch nicht zu 100% automatisiert werden können. Jemand muss irgendwo angeben, wie diese Ableitung erfolgen soll; Je nach Klasse muss der Benutzer möglicherweise die Last tragen, da Informationen vorliegen, auf die grundsätzlich nicht geschlossen werden kann.

In Ihrem Fall entspricht der Newtype Containerrepräsentativ der IdentityMonade in der Standardbibliothek, sodass Sie Folgendes verwenden können DerivingVia:

{-# LANGUAGE DerivingVia #-}
import Data.Functor.Identity

newtype Container a = Container a deriving (Functor, Applicative, Monad) via Identity

In dieser speziellen Situation gibt es nur eine sinnvolle Instanz, aber meistens ist es nicht einfach zu sagen, wie die Instanz aussehen soll, selbst wenn es nur eine gibt.

Li-yao Xia
quelle
Sie müssen auch ableiten Functorund Applicative, aber dann den Typ von Container 3 >>= (+1)mit vergleichen Identity 3 >>= (+1). Ich weiß nicht, ob das damit zusammenhängt DerivingViaoder nicht.
Chepner
(Für den Fall, dass ich etwas Seltsames mache, bekomme ich Container 3 >>= (+ 1) :: Num (Container b) => Container bund Identity 3 >>= (+ 1) :: Num b => Identity b. Ich bin mir nicht sicher, warum Container b, anstatt bdie NumEinschränkung zu haben.)
chepner
Danke für die Präzision. Was Ihre zweite Bemerkung (+ 1) :: Num c => c -> cbetrifft (+ 1) :: a -> Container b, müssen Sie sich vereinen , um einen Kleisli-Pfeil zu haben c ~ Container b. Aber ich bin mir nicht sicher, womit Sie anfangen sollen.
Li-yao Xia
Ich frage mich nur , was definiert ist für Identitydie nicht definiert ist Container, als Identity 3 >>= (+1)auswertet zu Identity 4.
Chepner
Es ist nur, weil es eine instance Num a => Num (Identity a)definierte gibt.
KA Buhr