2011-06-27 19 views
7

Hoopl kitaplığını kullanıyorum ve yeniden yazarken bazı durumları taşımak istiyorum. Yeniden yazma işlevleri kullanılan monad ile ilgili polimorfiktir, ancak bir State monadını kütüphanenin Fuel monad'larından biriyle nasıl birleştireceğimi anlayamıyorum.CheckingFuelMonad'ı Hoopl'da bir devlet monadıyla nasıl birleştirebilirim?

Aşağıda minimal bir örnek verilmiştir. MyMonad, Hoopl'un CheckingFuelMonad ve bir bayrağı taşıyan bir State monadını bir araya getiren bir eşanlamlıdır. Stmt aramam için bir yer tutucudur ve gerçekten önemli değildir.

{-# LANGUAGE GADTs, RankNTypes #-} 

import Compiler.Hoopl 
import Control.Monad.State 

type MyMonad = CheckingFuelMonad (State Bool) 

data Stmt e x where 
    Bind ::() -> Stmt O O 

rewriter :: forall e x. Stmt e x -> Fact x() -> MyMonad (Maybe (Graph Stmt e x)) 
rewriter (Bind())() = return $ do 
    f <- get 
    if f 
    then return $ Just emptyGraph 
    else return Nothing 

Ama bu derlemek olmaz - GHC rewrite yanlış türe sahip yakınıyor:

Couldn't match expected type `Graph' Block Stmt e x' 
     against inferred type `Maybe (g n O O)' 
    Expected type: CheckingFuelMonad 
        (State Bool) (Maybe (Graph Stmt e x)) 
    Inferred type: CheckingFuelMonad 
        (State Bool) (Maybe (Maybe (g n O O))) 

Mümkün yapmak istediğim şey var mı? rewrite işlevini nasıl doğru yazabilirim?

+0

Bu yeniden yazmanın sağlam olduğuna inanıyorum. Bu çok tehlikeli bir iş. –

cevap

4

Hoopl koduna göz atma, CheckingFuelMonad'ın MonadTrans'ın bir örneği olmadığını ve yapıcıların dışa aktarılmadığı için bunu yapamazsınız. Sen ancak şöyle, CheckingFuelMonad etrafında bir Durumluk sarabilirsiniz:

{-# LANGUAGE GADTs, RankNTypes #-} 

import Compiler.Hoopl 
import Control.Monad.State 

type MyMonad = StateT Bool SimpleFuelMonad 

data Stmt e x where 
    Bind ::() -> Stmt O O 

rewriter :: forall e x. Stmt e x -> Fact x() -> MyMonad (Maybe (Graph Stmt e x)) 
rewriter (Bind())() = do 
    f <- get 
    if f 
    then return $ Just emptyGraph 
    else return Nothing 
+0

Komik bölüm, "CheckingFuelMonad" uygulamasına bakarsanız, sadece "StateT Fuel" in kendisi. –

+0

Bu, biraz daha uzaklaşmama yardımcı oluyor! Ne yazık ki 'MyMonad '' FuelMonad'ın bir örneği olmalı ve sınıf üyeleri ihraç edilmediğinden beri bunu yapabileceğimi sanmıyorum. Ancak, 'mkBRewrite (\ s f -> evalStateT (rewriter s f) False) ile uzaklaşabiliyorum. Maalesef bunun devletin bireysel ifadeler karşısında korunmayacağı anlamına geldiğini düşünüyorum - göreceğiz! –

+0

@Justin Bailey: FuelMonad'ın her şey bana ihraç edilmiş gibi görünüyor. Ayrıca, emrin * bitişik * 'StateT' katmanları için alakasız olduğundan eminim, bu yüzden 'sclv' versiyonu' State' 'SimpleFuelMonad' içine koymakla eşdeğer olmalıdır. –

1

Peki, mevcut hatanın derhal nedeni basittir. f doğruysa son ifade nedir? Eğer buna:

rewriter :: forall e x. Stmt e x -> Fact x() -> MyMonad (Maybe (Graph Stmt e x)) 
rewriter (Bind())() = return $ do 
    f <- get 
    if f 
    then return $ Just emptyGraph 
    else return Nothing 

... ve True dalı ama her şeyi kaldırın elde ederiz:

rewriter :: forall e x. Stmt e x -> Fact x() -> MyMonad (Maybe (Graph Stmt e x)) 
rewriter (Bind())() = return $ do 
    return $ Just emptyGraph 

... için basitleştiren:

rewriter :: forall e x. Stmt e x -> Fact x() -> MyMonad (Maybe (Graph Stmt e x)) 
rewriter (Bind())() = return $ return $ Just emptyGraph 

tipi nedir return $ return $ Just emptyGraph?

(Monad m1, Monad m2, GraphRep g) => m1 (m2 (Maybe (g n O O))) 

Başka bir deyişle, orada fazladan bir return var. (Monad m) => CheckingFuelMonad m, CheckingFuelMonad'un bir monad trafosu olarak tanımlanmasa bile, Monad'un kendisi olduğu için, return ile yalnızca bir monad katmanınız vardır.

+0

Bir geri dönüşün başka bir tür hatayla sonuçlandığını bildiren ... :( –

+0

@Justin Bailey: Bu yüzden neden "acil neden" dedim. 'Geri' bloğunun dışındaki 'dönüş' 'ün kaldırılması sadece gerçek problemi azaltır. ne hakkında konuşuyorsun? –

İlgili konular