type InterpreterMonad = ErrorT String ((StateT (Stack EnvEval)) IO)
argsToContext :: [DefArg] -> [CallArg] -> InterpreterMonad ()
argsToContext xs ys = argsToContext' xs ys Map.empty where
argsToContext' ((ArgForDefinition t name):xs) ((ArgForCall e):ys) m = get >>= \contextStack -> (argsToContext' xs ys (Map.insert name e m ))
argsToContext' [] [] m = get >>= \contextStack -> (put (push contextStack m)) >>= \_ -> return ()
data DefArg =
ArgForDefinition Type VarName
data CallArg =
ArgForCall Evaluable
嗨,
我在理解上面的Haskell代码
时遇到了问题特别是,我无法理解它是如何return ()
以及它放在这里的原因。
请解释。
答案 0 :(得分:3)
return
并不意味着它在C或Java等命令式语言中意味着什么。事实上它的确是错误的名称,但由于历史原因,我们坚持使用它。更好的名字将是“纯粹的”或“包裹”,这意味着它需要一个纯粹的价值并将其包含在monadic环境中。
()
类型称为“单位”。它实际上并不是空的,因为它有一个值,也称为()
(因此得名)。但是它是空的,因为当你不想传达任何信息时使用它:只有一个值,所以它需要零位来表示它。 (当你真的不希望它有任何值时,可以使用“Void”类型。)
所以return ()
意味着这个monadic动作将一个单元包含在monadic上下文中。实际上它是一个无操作:什么都不做,不返回任何信息。
在这种情况下,它用于参数是两个空列表的情况。 argsToContext'
的工作是将DefArg
列表与CallArg
列表配对。第一个定义采用每个列表的头部,用它们做它的事情,然后用每个列表的尾部调用它自己。当尾部都为空时,它调用第二个版本,它将结果上下文放在上下文堆栈的顶部。如果两个列表的长度不同,那么它将抛出异常,因为两个模式都不匹配。如果它是你的代码,那么你应该放入一个防御性案例,部分是为了帮助你调试,部分是为了表明你实际上考虑过这个案例,部分是为了阻止编译器唠叨你。
这种情况下的'上下文'是解释器的变量,它们保存在Map
中。因此argsToContext'
的唯一影响是将这些对添加到上下文中,然后返回“单位”值。 InterpreterMonad
是monadic类型,返回值的类型为InterpreterMonad ()
,这意味着不返回任何信息,它只在monadic上下文中有副作用。
事实上,我认为您不需要return ()
,因为put
已经为您所在的monad提供了类型m ()
。所以只需删除>>= \_ -> return ()
和我认为它会正常工作。