2017-02-09 5 views
1

Ich werde durch den Staat Monade here und ich versuche zu implementieren:Datenkonstruktorfehler bei der Implementierung von State Monad?

import Control.Monad.Reader 
import Control.Monad.Writer 
import Control.Monad.State 

type Stack = [Int] 

pop :: State Stack Int 
pop = State $ (x : xs) -> (x, xs) 

aber ich folgende Fehlermeldung bin immer:

"Data constructor not in scope: 
    State :: ([t0] -> (t0, [t0])) -> State Stack Int 
Perhaps you meant one of these: 
    ‘StateT’ (imported from Control.Monad.State), 
    variable ‘state’ (imported from Control.Monad.State)" 

Bin ich etwas Grundsätzliches hier fehlt?

Antwort

4

Nein, Sie sind es nicht. Das Tutorial vereinfacht die Dinge ein wenig ( oder vielleicht ist es nur veraltet - ich gehe nicht weit genug zurück, um zu wissen, welche der beiden es veraltet ist). Control.Monad.State definiert eine Monade TransformatorStateT. Es exportiert auch eine einfachere Art Synonym entspricht dem, was das Tutorial Sie

type State s a = StateT s Identity a 

jedoch lehrt, bedeutet das, dass der Konstruktor ist nicht State, es ist StateT (und es hat eine verallgemeinerte Signatur). Zum Glück müssen Sie sich im Moment nicht allzu viele Sorgen machen.

  • Für den Bau State, können Sie die state Funktion verwenden und so tun es die Unterschrift state :: (s -> (a,s)) -> State s a hat (in Wirklichkeit ist es eine allgemeine Signatur hat - was Sie über Fehlermeldungen kommen).
  • Zum Dekonstruieren State verwenden Sie einfach runState :: State s a -> s -> (a,s) statt Mustervergleich.

Aus dem Beispiel Sie haben:

import Control.Monad.Reader 
import Control.Monad.Writer 
import Control.Monad.State 

type Stack = [Int] 

pop :: State Stack Int 
pop = state $ \(x : xs) -> (x, xs) 
+1

Danke Alec, sehr klar - ich bin froh, dass ich in meinem Alter nicht wählerisch werde! –

+0

[Das verknüpfte Lernprogramm ist veraltet und vereinfacht die Dinge nicht.] (Http://hackage.haskell.org/package/mtl-1.0/docs/Control-Monad-State.html # t: State) Es gab eine Zeit, in der die Leute befürchteten, dass Transformatoren, die auf 'Identity' aufbauten, im Vergleich zur direkten Definition der entsprechenden Monade zu Laufzeitkosten führten und so viele Bibliotheken (einschließlich mtl) sowohl eine Monade als auch ihren Transformator lieferten. Letztendlich hat sich das Argument der Codeverdopplung/-pflege gegen dieses Argument durchgesetzt. –

2

Warum nehmen Sie an, dass die Schnittstelle zu State a durch einen Datenkonstruktor ist, der eine Funktion s -> (a, s) umschließt? Das ist ein einfacher Weg zu implementieren State, aber Sie sind nicht diese Schnittstelle zur Verfügung gestellt. Verwenden Sie stattdessen die Konstrukte, die in Control.Monad.State bereitgestellt werden.

Eine einfache Änderung ist nur den Klein verwendet state Funktion für diesen Zweck konzipiert:

pop :: State Stack Int 
pop = state $ \(x : xs) -> (x, xs) 

Alternativ kann statt mit dieser Low-Level-Ansicht des Staates arbeiten, können Sie mit ihm als Arbeits Monade durch seine put und get Funktionen:

pop :: State Stack Int 
pop = do 
    (x : xs) <- get 
    put xs 
    return x 
+2

Sie ist die Schnittstelle zu 'State' unter der Annahme, denn das ist, was das Tutorial sagt. :/"Das' Control.Monad.State'-Modul stellt einen neuen Typ bereit, der stateful Berechnungen umschließt. Hier ist seine Definition: 'newtype Zustand s a = Zustand {runState :: s -> (a, s)}' ". – Alec

+0

Ich frage mich, ob ein Muster Synonym ratsam wäre, um die "Illusion" des Arbeitens mit einem einfacheren 'State' mit einer einfachen Schnittstelle zu exportieren. Mit sicheren Zwängen sollte es keine Laufzeitkosten haben, denke ich. Dies könnte auf die meisten Monaden-Transformatoren ausgedehnt werden, die auf "Identität" angewendet werden. – chi

Verwandte Themen