2016-10-26 2 views
1

Ich habe einen Datentyp, der Blah unten ähnelt, aber wegen einer Eigenart mit dem Typ kann ich nicht automatisch Functor, Applicative und Monad ableiten. Also muss ich es manuell machen, aber ich weiß nicht wie. Ich habe versucht, mich von den Instanzen für ((->) a) inspirieren zu lassen, aber ich kann die Monad-Instanz nicht genau herausfinden.Applicative- und Monad-Instanzen für einen Funktionstyp?

Edit: Jemand markiert dies als ein Duplikat von einem anderen, aber ich sehe nicht, wo ich die Antwort bekommen hätte. Der Wrapper des neuen Typs hat das schwierig gemacht. Ich habe die Monad Instanz in der Basis für (->) a gesucht, bevor ich diese Frage geschrieben habe, aber die Gymnastik in der Antwort hier sind, was ich brauchte.

+1

definieren. Warum wurde dies markiert? Es scheint eine vollkommen gute Frage zu sein. –

+0

Mögliche Duplikate von [Wie zu verwenden (->) Instanzen von Monad und Verwirrung über (->)] (http://stackoverflow.com/questions/5310203/how-to-use-instances-of-monad-and- Verwirrung-über) – Cactus

Antwort

3

Wie

über
Blah f >>= g = Blah $ \s -> 
    let Blah h = g $ f s in h s 
+0

Genau das, was ich gesucht habe. Vielen Dank! –

+4

Dies ist die 'Reader String'-Monade – pat

+0

Ich wusste, dass es irgendwo ein gutes Beispiel für genau das gibt, aber ich konnte mir keinen vorstellen. –

2

Sie können derive diese Instanzen. Sie müssen nur das Flag GeneralizedNewtypeDeriving aktivieren, wodurch GHC die Instanz für den Wrapped-Typ einfach wiederverwenden kann.

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 

newtype Blah a = Blah (String -> a) deriving (Functor, Applicative, Monad) 
+0

Wie ich in meinem ursprünglichen Beitrag sagte, kann ich nicht ableiten.Dies liegt daran, dass ich Klassenbeschränkungen für den Typ in meinem tatsächlichen Programm habe. Es ist auch kein neuer Typ. –

+6

In diesem Fall geben Sie bitte den _actual_ Code, den Sie haben. –

+0

Der tatsächliche Typ ist wirklich groß und zu kompliziert und wenn ich es hier setze, wird es nicht stundenlang oder vielleicht den Rest des Tages beantwortet werden. Ich möchte nur, dass dieser einfache Code in einer angemessenen Zeit beantwortet wird, damit ich den Rest des Tages (der an diesem Punkt weit offen steht) an meinem Programm arbeiten kann, anstatt herumzusitzen und zu warten. –

1

Hier ist, wie Sie diese ableiten können selbst eingegeben Löcher verwenden. Ausgehend von Ihrem Code umbenannt ein bisschen:

instance Monad Blah where 
    return = pure 
    f >>= g = Blah $ \s -> _ 

Sie erhalten eine Nachricht wie diese:

Found hole ‘_’ with type: b 
Relevant bindings include 
    s :: String 
    g :: a -> Blah b 
    f :: Blah a 

Also brauchen wir eine b zu produzieren, da ein String, ein Blah a und ein a -> Blah b . Nun, wir wissen schon, wie ein a von einem Blah a zu produzieren und zu einem String, durch Pattern-Matching und Anwendung der Funktion in der Blah:

Blah f >>= g = Blah $ \s -> let h = f s in _ 
------      ----------- 

Jetzt erhalten wir:

Found hole ‘_’ with type: b 
Relevant bindings include 
    h :: a 
    s :: String 
    g :: a -> Blah b 
    f :: String -> a 

So haben wir

Blah f >>= g = Blah $ \s -> let Blah h = g (f s) in _ 
           ---------------- 
: ein a, die wir g geben kann ein Blah b und pattern-Matching auf das gibt uns eine String -> b zu erhalten Jetzt

erhalten wir:

Found hole ‘_’ with type: b 
Relevant bindings include 
    h :: String -> b 
    s :: String 
    g :: a -> Blah b 
    f :: String -> a 

Also brauchen wir ein b, und wir haben eine String und String -> b. Das ist einfach:

Und da gehen Sie, eine korrekte Implementierung, von den Typen geführt. Sie können es auch klarer finden, wenn Sie eine Hilfsfunktion zum "Ausführen" eines Blah: