Wie in den Zustand von Funktionen zu verbergen, die andere Funktionen aufrufen, die diesen Zustand nutzen

stimmen
1

Ich möchte einige Funktionen höherer Ebene in meinem Haskell Programmaufruf andere Funktionen haben, die schließlich Funktionen aufrufen, die einige Zustand oder Konfiguration verwenden, und nicht den Staat um alle diese Funktionsaufrufe übergeben. Ich verstehe dies eine klassische Verwendung des Staates Monade ist (oder möglicherweise der Reader Monade?).

(Ich bin auch nicht sicher, ob es (wie in meinem Beispiel unten StateT werden soll) zu tun IO zu aktivieren, oder wenn die Ergebnisse irgendwie getrennt ausgegeben werden sollen.)

In diesem Stadium bin ich ziemlich verwirrt von allen Tutorials, Blog-Posts und ähnlichen Fragen hier und kann nicht die Lösung auswählen. Oder habe ich das falsch verstanden, die versteckt, was?

Hier ist ein kleines Beispiel:

import Control.Monad.State

-- Here's a simple configuration type:
data Config = MkConfig {
      name :: String
    , num  :: Int
    } deriving Show

-- Here's a couple of configurations.
-- (They're hard coded and pre-defined.)
c1 = MkConfig low 7
c2 = MkConfig high 10

-- Here's a lower level function that explicitly uses the config.
-- (The String is ignored here for simplicity, but it could be used.)
fun :: Config -> Int -> Int
fun (MkConfig _ i) j = i*j

-- testA and GoA work fine as expected.
-- fun uses the different configs c1,c2 in the right way.
testA = do
    a <- get
    lift (print (fun a 2))
    put c2
    a <- get
    lift (print (fun a 4))

goA = evalStateT testA c1
-- (c1 could be put at the start of testA instead.)

-- But what I really want is to use fun2 that calls fun, 
-- and not explicitly need state.
-- But this function definition does not compile:
fun2 :: Int -> Int
fun2 j = 3 * fun cf j  
-- fun needs a config arg cf, but where from?

-- I would like a similar way of using fun2 as in testB and goB here.
testB = do
    a <- get
    lift (print (fun2 3))  -- but fun2 doesn't take the state in a 
    put c2
    a <- get
    lift (print (fun2 42))  -- but fun2 doesn't take the state in a 

goB = evalStateT testB c1 

Ich mag die Konfiguration weg wie fun2 in meinem Programm aus den höheren Funktionen verbergen, während immer noch die Fähigkeit beibehalten Konfiguration zu ändern und die Funktionen mit der neuen Konfiguration laufen. Dies ist eine ‚wie es zu tun Frage‘ (es sei denn, ich die falsche Idee völlig habe).

Veröffentlicht am 20/10/2018 um 12:28
quelle vom benutzer
In anderen Sprachen...                            


1 antworten

stimmen
2

Sie können nicht ganz „verstecken die Konfiguration weg“ in der Art Unterschrift, natürlich: eine einfache alte Funktion Int -> Intreferentiell transparent sein muss, und so kann es nicht auch davon abhängen , oder etwas akzeptieren ConfigWert.

Was Sie wahrscheinlich tun wollen, ist so etwas wie:

fun2 :: Int -> State Config Int    -- An `Int -> Int` that depends on `Config` state.
                                   -- Compare to how `Int -> IO Int` is like an
                                   -- `Int -> Int` function that depends on IO.
fun2 j = do
  c1 <- get
  return (3 * fun c1 j)

Und dann , wo immer Sie eine haben c :: Config, können Sie das Ergebnis von etwas bekommen wie

let result = evalState (fun2 42) c    -- An Int.

Siehe auch StateT IO mit Staat Kombination :

hoistState :: Monad m => State s a -> StateT s m a
hoistState = StateT . (return .) . runState

Dann können Sie so etwas wie schreiben

testB :: StateT Config IO ()
testB = do
    -- Fancy:
    result <- hoistState (fun2 42)

    -- Equivalent:
    c <- get
    let result' = evalState (fun2 42) c

    lift (print (result, result'))
Beantwortet am 20/10/2018 um 14:04
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more