2011-04-19 3 views
3

대부분이 힌트 예제에서 나온 것입니다. 내가하고 싶은 것은 모듈과 수입 등으로 통역사를 초기화하고 어떻게 든 유지하는 것입니다. 나중에 (사용자 이벤트 등), 초기화 된 상태로 함수를 호출하고 표현을 여러 번 해석 할 수 있기를 원합니다. 그래서 코드의 --split 위치에, 위의 코드를 init에 넣고, 아래 코드는 표현식을 취하고 해석하는 새로운 함수에 넣고 싶습니다.모나드를 초기화 한 다음 하스켈에서 함수를 여러 번 사용하는 방법

module Main where 
import Language.Haskell.Interpreter 
import Test.SomeModule 

main :: IO() 
main = do r <- runInterpreter testHint 
      case r of 
      Left err -> printInterpreterError err 
      Right() -> putStrLn "Done." 
      -- Right here I want to do something like the following 
      -- but how do I do testInterpret thing so it uses the 
      -- pre-initialized interpreter? 
      case (testInterpret "expression one") 
      Left err -> printInterpreterError err 
      Right() -> putStrLn "Done." 
      case (testInterpret "expression two") 
      Left err -> printInterpreterError err 
      Right() -> putStrLn "Done." 

testHint :: Interpreter() 
testHint = 
    do 
     loadModules ["src/Test/SomeModule.hs"] 
     setImportsQ [("Prelude", Nothing), ("Test.SomeModule", Just "SM")] 
     say "loaded" 
     -- Split here, so what I want is something like this though I know 
     -- this doesn't make sense as is: 
     -- testExpr = Interpreter() -> String -> Interpreter() 
     -- testExpr hintmonad expr = interpret expr 
     let expr1 = "let p1o1 = SM.exported undefined; p1o2 = SM.exported undefined; in p1o1" 
     say $ "e.g. typeOf " ++ expr1 
     say =<< typeOf expr1 


say :: String -> Interpreter() 
say = liftIO . putStrLn 

printInterpreterError :: InterpreterError -> IO() 
printInterpreterError e = putStrLn $ "Ups... " ++ (show e) 

답변

3

질문 이해에 어려움이 있습니다. 또한 나는 힌트에 익숙하지 않다. 그러나 나는 그것을 줄 것이다.

내가 말할 수있는 한, Interpreter 모나드는 간단한 상태 래퍼 IO에 불과합니다. 예를 들어 말할 수 있도록 존재합니다. setImportsQ [...]과 그 이후의 계산은 해당 함수에 의해 수정 된 "설정"에 따라 달라집니다. 따라서 기본적으로 여러 계산의 모나드 컨텍스트를 공유하려고합니다. 이를 수행하는 유일한 방법은 모나드에 머무름으로써 - Interpreter에 단일 계산을 작성하고 한 번 실행하는 것입니다. runInterpreter을 이스케이프하고 다시 사용하는 "전역 변수"를 가질 수 없습니다.

다행히 InterpreterliftIO :: IO a -> Interpreter a를 사용 IO 계산 및 Interpreter 계산을 인터리브 수 있다는 것을 의미 MonadIO의 인스턴스이다. 기본적으로 당신은 안쪽 밖으로 생각하고 있습니다 (하스켈의 학습자에게는 매우 흔한 실수입니다). 인터프리터에서 코드를 실행하는 IO의 함수를 사용하는 대신 IO (즉 liftIO)의 코드를 실행하는 Interpreter의 함수를 사용하십시오. 그래서 예.

main = runInterpreter $ do 
    testHint 
    expr1 <- liftIO getLine 
    r1 <- interpret "" expr1 
    case r1 of 
     ... 
    expr2 <- liftIO getLine 
    r2 <- interpret "" expr2 
    case r2 of 
     ... 

그리고 참조 투명도의 아름다움을 사용하여 필요할 경우 쉽게 후자 코드를 함수로 가져올 수 있습니다! 그냥 똑바로 당겨.

runSession :: Interpreter() 
runSession = do 
    expr1 <- liftIO getLine 
    r1 <- interpret "" expr1 
    case interpret expr1 of 
     ... 

main = runInterpreter $ do 
    testHint 
    runSession 

의미가 있습니까? 귀하의 전체 프로그램Interpreter이며, 마지막 순간에만 IO으로 추출합니다.

(즉 하지 당신이 쓰는 모든 기능은 Interpreter 모나드에해야한다고. 그것에서 멀리! 평소와 같이, 프로그램의 가장자리 주위에 Interpreter을 사용하고 순수하게 기능적인 핵심을 유지하는 것을 의미한다. Interpreter 새로운 IO입니다 않습니다).

3

올바르게 이해하면 컴파일러를 한 번 초기화하고 여러 쿼리를 대화식으로 실행할 수 있습니다.

  • 리프트 당신의 Interpreter 상황에 IO 행동 (luqui의 답변을 참조)

    는 두 가지 방법이 있습니다.

  • 지연 입출력을 사용하여 프로그램 안팎으로 데이터 스트림을 밀입국 시키십시오.

두 번째 옵션에 대해 설명하겠습니다. 게으른 IO의 마법으로


, 당신은 대화 형으로 많은 쿼리를 해석, 입력 게으른 스트림, testHint의 본문에 다음 루프를 testHint 전달할 수 있습니다

main = do 
     ls <- getContents -- a stream of future input 
     r <- runInterpreter (testHint (lines input)) 
     case r of 
     Left err -> printInterpreterError err 
     Right() -> putStrLn "Done." 

testHint input = do 
     loadModules ["src/Test/SomeModule.hs"] 
     setImportsQ [("Prelude", Nothing), ("Test.SomeModule", Just "SM")] 
     say "loaded" 

     -- loop over the stream of input, interpreting commands 
     let go (":quit":es) = return() 
      (e:es)  = do say =<< typeOf e 
           go es 
     go 

go 기능에 액세스 할 수 있습니다 초기화 된 인터프리터의 클로즈드 환경이므로 이벤트를 제공하는 것은 일단 초기화 된 인터프리터의 범위에서 분명히 실행됩니다.

대체 방법은 모나드에서 해석기 상태를 추출하는 것이지만 GHC에서는 가능합니다 (GHC가 IO 모나드에 없기를 요구합니다).

+0

나는 내 질문을 조금 변경하여 내가하려는 일에 대해 더 잘 보여주고있다. 나는 당신이 가고있는 곳을 보았다고 생각하지만, 나중에 그 스트림에 뭔가를 집어 넣고 어떻게 결과를 되 찾을 수 있을지 모르겠습니다. (오류인지 아닌지). – mentics

+0

함수에 통신 채널이 있으면'go' 루프가 이벤트를 처리합니다. 대신에 (입력과 출력 모두에 대해) 명시 적 Chan 유형을 사용할 수 있습니다. –

관련 문제