Haskell中的副作用和I/O.

neb*_*ffa 1 haskell

好的,我是Haskell IO的新手.我在Haskell函数中已经阅读了很多关于IO和副作用的内容,现在我已经在Haskell中做了我自己的一些副作用,我想知道 - 我该如何写这些东西?

我有以下功能,因此在运行其中一行代码之后,我想进行一些打印,这可以通过前几行中的注释来解释.

我很确定我需要更改函数的类型签名,也许我需要使用Maybe.也许它甚至不可能这样做,我必须完全重写它?我真的不知道 - 但我正在寻找指导.我该如何使用此功能?

interpret_statement :: Prog -> Vars -> Stmt -> Vars -- one third of the debug -d functionality goes here 
                                                    -- AFTER every assignment is executed, the interpreter should print a line specifying
                                                    -- the variable being assigned to AND its new value
interpret_statement prog vars@(Vars _ b c d) (Assign A expr) = Vars (interpret_expr prog vars expr) b c d
interpret_statement prog vars@(Vars a _ c d) (Assign B expr) = Vars a (interpret_expr prog vars expr) c d
interpret_statement prog vars@(Vars a b _ d) (Assign C expr) = Vars a b (interpret_expr prog vars expr) d
interpret_statement prog vars@(Vars a b c _) (Assign D expr) = Vars a b c (interpret_expr prog vars expr)
Run Code Online (Sandbox Code Playgroud)

dav*_*420 5

我将从Adrian的答案开始.

interpret_statement :: Prog -> Vars -> Stmt -> IO Vars
interpret_statement prog vars@(Vars _ b c d) (Assign A expr) = do
    print "some debug"
    return $ Vars (interpret_expr prog vars expr) b c d
-- etc
Run Code Online (Sandbox Code Playgroud)

这是正确的,但有一些问题:

  • 调试输出是强制性的,但可能你希望它是可选的
  • 虽然我们需要结果类型来IO Vars执行i/o,但这使得测试更加困难interpret_statement

一个办法:

  • 添加一个函数参数来interpret_statement执行任何所需的i/o
  • 使该函数具有多态性,以便其结果类型确定结果类型 interpret_statement

例如(原谅我猜你的类型:我假设data VarName = A | B | C | Ddata Vars = Vars Value Value Value Value):

interpret_statement :: (VarName -> Value -> Vars -> o) ->
                       Prog -> Vars -> Stmt -> o
interpret_statement debug prog vars@(Vars _ b c d) (Assign A expr)
    = debug A newValue $ Vars (interpret_expr prog vars expr) b c d
-- etc
Run Code Online (Sandbox Code Playgroud)

您可以提供的有用功能是:

purePassthrough :: VarName -> Value -> Vars -> Vars
purePassthrough _ _ vars = vars
Run Code Online (Sandbox Code Playgroud)
  • interpret_statement从QuickCheck测试时使用,并希望它是纯净的
  • interpret_statement purePassthrough :: Prog -> Vars -> Stmt -> Vars,就像你原来的一样 interpret_statement
writeDebuggingInfo :: VarName -> Value -> Vars -> IO Vars
writeDebuggingInfo varName newValue newVars = do
    putStrLn $ show varName ++ " := " ++ show newValue
        -- or whatever debugging output you want
    return newVars
Run Code Online (Sandbox Code Playgroud)
  • 在需要编写调试信息时在程序中使用
  • interpret_statement writeDebuggingInfo :: Prog -> Vars -> Stmt -> IO Vars,就像阿德里安的回答一样
dontWriteDebuggingInfo :: VarName -> Value -> Vars -> IO Vars
dontWriteDebuggingInfo :: _ _ newVars = return newVars
Run Code Online (Sandbox Code Playgroud)
  • interpret_statement dontWriteDebuggingInfo :: Prog -> Vars -> Stmt -> IO Vars,与前一种情况一样
  • 当你可能想要或不想要调试输出时使用,例如

    newVars <- interpret_statement (if wantDebuggingOutput then writeDebuggingInfo
                                                      else dontWriteDebuggingInfo)
                   program vars statement
    
    Run Code Online (Sandbox Code Playgroud)