好的,我是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)
答案 0 :(得分: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
这是正确的,但有一些问题:
IO Vars
才能执行i / o,但这会让测试更加困难interpret_statement
解决方案:
interpret_statement
interpret_statement
e.g。 (原谅我猜测你的类型:我假设data VarName = A | B | C | D
和data 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
您可以提供的有用功能是:
purePassthrough :: VarName -> Value -> Vars -> Vars
purePassthrough _ _ vars = vars
interpret_statement
时使用
并希望它是纯粹的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
interpret_statement writeDebuggingInfo :: Prog -> Vars -> Stmt -> IO Vars
,
如在阿德里安的回答中dontWriteDebuggingInfo :: VarName -> Value -> Vars -> IO Vars
dontWriteDebuggingInfo :: _ _ newVars = return newVars
interpret_statement dontWriteDebuggingInfo :: Prog -> Vars -> Stmt -> IO Vars
,
与前一个案例一样在您可能想要或不想要调试输出时使用,例如
newVars <- interpret_statement (if wantDebuggingOutput then writeDebuggingInfo
else dontWriteDebuggingInfo)
program vars statement
答案 1 :(得分:4)
你是对的。如果你想做一些打印,你的代码必须存在于一些monad中。 Monad负责处理现实世界的操作 - 比如在屏幕上打印 - 是IO monad。因此,要使用putStrLn, print, getLine
之类的函数,您需要将函数签名更改为:
interpret_statement :: Prog -> Vars -> Stmt -> IO Vars
并使用do
表示法。函数的结果必须由return
函数包装,但我相信你已经知道了monad。
例如:
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