2013-05-21 25 views
5

Üniversite için bir ödev yazma sürecinde, yeni Haskell monad'larını öğrenmenin her zaman zevkli eğlencesini yaşıyorum. Yuppi!!!Haskell State Monad'ın dağıtılması

ben gayet typechecks bir işlevi vardır:

compile :: Prog -> State VarsState String 
compile [email protected](Prog functions) = do 
    s1 <- sequence (map (translate_func 0) [get_function prog name | name <- [func_name func | func <- functions]]) 
    return $ trace ("here's the program: \n" ++ show prog) $ concat $ s1 

ama bu başka fonksiyon zaman:

maybe_compile_prog :: 
    MaybeOK Prog -> String -> IO() 
maybe_compile_prog (Error msg) _ = do 
    putStrLn ("error: " ++ msg) 
maybe_compile_prog (OK prog) modulename = do 
    s1 <- compile prog 
    writeFile (modulename ++ ".m") ((header modulename) ++ s1) 

çalışır adlandırmak, bu hat

s1 <- compile prog 
kadar darbeler

, gerçek tip "State VarsState String" ile beklenen tür "IO t0" ile eşleşemediğini söyler.

Bunun sebebi, belki de ben_compile_prog IO() tipini döndürdüğünden, IO bilgilerini yalnızca açmayı umduğundan varsayıyorum. VarsState, State monad/

ile birlikte kullandığım özel bir veri türüdür. Ancak, sorun buysa ve varsayalım, bu basit dizgiyi belki_compile_prog dosyasına nasıl aktaracağımı bilmiyorum. Gerçekten, tüm yapmak istediğim şey budur - belki de belki de bir_ilgile.

Belki de bu devlet monadını açmak için düzgün bir yol var mı? Belki de “derleme” yi yeniden yazabilir, böylece çalışır durumdayken bazı durum bilgisi bilgisini alır, ancak daha sonra sadece bir dize döndürür (herhangi bir monoya sarılmaz)?

Herhangi bir bilgi eksikse lütfen bana bildirin.

cevap

11

compile progState VarsState Monad'daki bir eylemdir, bu nedenle IO -do-bloğu içinde kullanamazsınız. Bir blokta, tüm satırlar aynı monad'i kullanmalıdır, bu durumda IO.

Sen

  • sadece yol açabilir ve son durum size

    • hem ihtiyaç olmadığına bağlı

      runState :: State s a -> s -> (a,s) 
      evalState :: State s a -> s -> a 
      execState :: State s a -> s -> s 
      

      biriyle, "run" compile eylem sonucu elde etmek için gereken

    • sadece son durum

    Senin durumunda, sadece sonucu istiyorsun, yani evalState öyle.

    bir başlangıç ​​durumunu sağlamak için gereken Bunun için

    , bu

    maybe_compile_prog (OK prog) modulename = do 
        let s1 = evalState (compile prog) initialState 
        writeFile (modulename ++ ".m") ((header modulename) ++ s1) 
    

    gibi görünebilir ama sonra compile eylem için sağlanan başlangıç ​​durumu geçirilen tüm OK prog s için aynı olacaktır. Bu doğru bir şey değilse, başlangıç ​​durumunu da parametre olarak geçirebilirsiniz.

  • +1

    Mükemmel dostum. Küçük bir şey hariç, "let s1 = evalState (derleme prog) initialState" ile derleme, "let s1 = evalState $ derleme prog initialState". Bir başka soru - diğer monadlar için böyle işler var mı? yani monad'ı açıp sadece sonucu döndüren işlevler? – nebffa

    +0

    @nebffa tamamen söz konusu monoya bağlıdır, ancak evet, bazıları.Bütün monadlar için genel olarak yapabileceğiniz bir şey değil. Bir başka örnek de, “IO” monadının korkusuz “güvensizPerformi” olması olurdu, ama bunu kullanmamalısınız. –

    +0

    Ah, evet, parantezleri karıştırın (önce durumu unuttun, ve eklerken '$' yi değiştirmeyi unutmayın). Head-up için teşekkürler. Birçok monad için, karşılık gelen fonksiyonlar vardır, ancak hepsi için değil. 'IO', hiçbirinin olmadığı bir yerdi [iyi, 'güvenli olmayan' ile başlayan bir isim var ve gerçekten gerçekten anlam ifade ediyor]. "RunIdentity", "runReader", "runWriter", "runCont", ... vardır. Bu işlevlerin bulunup bulunmadığı her bir monad için belgelere bakın. –