2014-05-11 12 views
5

मेरे पास कुछ कोड है जो आदिम कार्यक्रमों का मूल्यांकन करता है। कार्यक्रम बयानों की एक सूची है (अभिव्यक्ति, ब्लॉक, वापसी कथन)। मूल्यांकन का परिणाम अंतिम मूल्यांकन अभिव्यक्ति है। इसके अलावा मूल्यांकनकर्ता को return कथन का ठीक से इलाज करना चाहिए (यानी return की पहली घटना के बाद मूल्यांकन रोकना)।निरंतरता के साथ कोड पुनर्लेखन

इस तर्क को लागू करने के लिए मैं विशेष कॉलबैक फ़ंक्शन (NextStep) पास करता हूं जो वर्तमान विवरण के बाद अगला मूल्यांकन चरण बनाता है।

data Statement = 
     Expr Int 
    | Block [Statement] 
    | Return Int 
    deriving (Show, Eq) 

data Value = 
     Undefined 
    | Value Int 
    deriving (Show, Eq) 

type NextStep = Value -> Value 

evalStmt :: Statement -> NextStep -> Value 
evalStmt (Expr val) next = 
    let res = Value val 
    in next res 
evalStmt (Block stmts) next = evalBlock stmts next 
evalStmt (Return val) next = Value val 

evalBlock :: [Statement] -> NextStep -> Value 
evalBlock [] next = next Undefined 
evalBlock [st] next = evalStmt st next 
evalBlock (st:rest) next = evalStmt st $ \ _ -> evalBlock rest next 

evalProgram stmts = evalBlock stmts id 

prog1 = [Expr 1, Block [Return 3, Expr 2], Expr 4] 
evalProg1 = evalProgram prog1 -- result will be Value 3 

सवाल यह है कि मैं निरंतरता इकाई के साथ इस कोड को फिर से लिखने सकता है: जब वापसी कथन से निपटने मैं अगले कदम कहें? मैं evalStmt और evalBlock कार्यों में स्पष्ट रूप से पास NextStep कॉलबैक से छुटकारा पाना चाहता हूं। क्या यह संभव है?

उत्तर

7

अनुवाद काफी यांत्रिक है।

ध्यान रखें कि निरंतरता में, return मूल्य को निरंतरता में फ़ीड करता है।

evalStmt :: Statement -> Cont Value Value 
evalStmt (Expr val) = 
    let res = Value val 
    in return res 
evalStmt (Block stmts) = evalBlock stmts 
evalStmt (Return val) = cont $ \_ -> Value val 

evalBlock :: [Statement] -> Cont Value Value 
evalBlock [] = return Undefined 
evalBlock [st] = evalStmt st 
evalBlock (st:rest) = evalStmt st >> evalBlock rest 

evalProgram :: [Statement] -> Value 
evalProgram stmts = runCont (evalBlock stmts) id 

और जल्दी रिटर्न अनुकरण करने के लिए, हम बस निरंतरता Return val को दी ध्यान न दें और सिर्फ मूल्य हमारे पास लौट आते हैं।

+2

'Cont' के लिए मोनैड इंस्टेंस को इस तरह श्रृंखला में परिभाषित किया गया है, ताकि * केवल * evalBlock (st: rest) = evalStmt st के बराबर होना चाहिए ... evalBlock rest' –

+0

@ ØrjanJohansen काफी सही! – jozefg

संबंधित मुद्दे