Monads返回空类型:return()

时间:2016-05-05 16:07:45

标签: haskell

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 ()以及它放在这里的原因。

请解释。

1 个答案:

答案 0 :(得分:3)

Haskell中的

return并不意味着它在C或Java等命令式语言中意味着什么。事实上它的确是错误的名称,但由于历史原因,我们坚持使用它。更好的名字将是“纯粹的”或“包裹”,这意味着它需要一个纯粹的价值并将其包含在monadic环境中。

()类型称为“单位”。它实际上并不是空的,因为它有一个值,也称为()(因此得名)。但是它是空的,因为当你不想传达任何信息时使用它:只有一个值,所以它需要零位来表示它。 (当你真的不希望它有任何值时,可以使用“Void”类型。)

所以return ()意味着这个monadic动作将一个单元包含在monadic上下文中。实际上它是一个无操作:什么都不做,不返回任何信息。

在这种情况下,它用于参数是两个空列表的情况。 argsToContext'的工作是将DefArg列表与CallArg列表配对。第一个定义采用每个列表的头部,用它们做它的事情,然后用每个列表的尾部调用它自己。当尾部都为空时,它调用第二个版本,它将结果上下文放在上下文堆栈的顶部。如果两个列表的长度不同,那么它将抛出异常,因为两个模式都不匹配。如果它是你的代码,那么你应该放入一个防御性案例,部分是为了帮助你调试,部分是为了表明你实际上考虑过这个案例,部分是为了阻止编译器唠叨你。

这种情况下的'上下文'是解释器的变量,它们保存在Map中。因此argsToContext'的唯一影响是将这些对添加到上下文中,然后返回“单位”值。 InterpreterMonad是monadic类型,返回值的类型为InterpreterMonad (),这意味着不返回任何信息,它只在monadic上下文中有副作用。

事实上,我认为您不需要return (),因为put已经为您所在的monad提供了类型m ()。所以只需删除>>= \_ -> return ()和我认为它会正常工作。