嵌套do块中令人困惑的类型失误错误
我正在尝试为一种简单的嵌入式脚本语言编写解释器。
它的核心是Eval函数,它具有以下签名。
type EvalState = () --for later
type EvalResult = State EvalState (IO (Either T.Text Value))
eval :: Expr -> EvalResult
结果类型之所以这样,是因为它是状态的,因此eval应该能够做到io,并且可能会失败。
有两个数据类型:表达式和值和评估将表达式转换为值。对于简单的表达式,原始数据类型的文字,它是这样实现的:
ok :: Value -> EvalResult
ok val = state (return . Right $ val,)
eval :: Expr -> EvalResult
eval (StrLit t) = ok (StrVal t)
eval (SymLit t) = ok (SymbolVal t)
eval (IntLit i) = ok (IntVal i)
eval (FloatLit f) = ok (FloatVal f)
我的问题现在是对列表的文字进行评估。目前,我的代码看起来像这样:
eval (ListLit elems) = do
elems <- mapM eval elems
do
opts <- sequence elems
return $ fmap (Right . ListVal . V.fromList) (sequence opts)
这会产生以下错误:
/home/felix/git/vmail/src/Interpreter/EvalAst.hs:37:13: error:
• Couldn't match type ‘IO’
with ‘StateT EvalState Data.Functor.Identity.Identity’
Expected: StateT
EvalState Data.Functor.Identity.Identity [Either T.Text Value]
Actual: IO [Either T.Text Value]
• In a stmt of a 'do' block: opts <- sequence elems
In a stmt of a 'do' block:
do opts <- sequence elems
fmap (Right . ListVal . V.fromList) (sequence opts)
In the expression:
do elems <- mapM eval elems
do opts <- sequence elems
fmap (Right . ListVal . V.fromList) (sequence opts)
|
37 | opts <- sequence elems
| ^^^^^^^^^^^^^^
我的问题是我不了解此错误。我的想法是这样的:第一个确实使我进入了州单元,因此我可以从mapm eval elems
中“提取”结果,我希望它是[io(要么要么...)]
下一个Do应该将我放在IO Monad中(因为这是结果类型中的下一个内部类型),因此我应该能够提取IO值,据我了解, sequence elems
应该给我一个io [...]
,我可以提取,那么我的错误是什么?
I'm trying to write an interpreter for a simple embedded scripting language.
The core of it is the eval function, which has the following signature.
type EvalState = () --for later
type EvalResult = State EvalState (IO (Either T.Text Value))
eval :: Expr -> EvalResult
The result type is like this because it is statefull, eval should be able todo IO and it can fail.
There are two datatypes: Expressions and Values and eval converts expression to values. For simple expressions, literals of primitive data types, it's implemented like this:
ok :: Value -> EvalResult
ok val = state (return . Right $ val,)
eval :: Expr -> EvalResult
eval (StrLit t) = ok (StrVal t)
eval (SymLit t) = ok (SymbolVal t)
eval (IntLit i) = ok (IntVal i)
eval (FloatLit f) = ok (FloatVal f)
My problem now is implementing eval for the list literal. Currently my code looks like this:
eval (ListLit elems) = do
elems <- mapM eval elems
do
opts <- sequence elems
return $ fmap (Right . ListVal . V.fromList) (sequence opts)
And this produces the following error:
/home/felix/git/vmail/src/Interpreter/EvalAst.hs:37:13: error:
• Couldn't match type ‘IO’
with ‘StateT EvalState Data.Functor.Identity.Identity’
Expected: StateT
EvalState Data.Functor.Identity.Identity [Either T.Text Value]
Actual: IO [Either T.Text Value]
• In a stmt of a 'do' block: opts <- sequence elems
In a stmt of a 'do' block:
do opts <- sequence elems
fmap (Right . ListVal . V.fromList) (sequence opts)
In the expression:
do elems <- mapM eval elems
do opts <- sequence elems
fmap (Right . ListVal . V.fromList) (sequence opts)
|
37 | opts <- sequence elems
| ^^^^^^^^^^^^^^
My problem is that I'm not understanding this error. My thinking goes like this: the first do puts me in the State monad, so I shold be able to "extract" the results from mapM eval elems
which I expect to be [ IO (Either ...) ]
The next do should put me in the IO monad (because that's the next inner type in the result type), so I should be able to extract IO values, and as far as I understood it, sequence elems
should give me a IO [ Either ... ]
which I can then extract, so what is my mistake?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一般而言,单子不构成。我认为您对此感到厌烦。
通常,如果
m
和n
是单子,我们将无法编写m(na)
用于混合m 和
n
。总的来说,它甚至可能失败了。在您的情况下,您正在使用
状态A(io b)
希望能够访问类型a
的状态,并且仍然做io
,但事实并非如此。实际上,根据定义,我们有(最多包装器):
在您的情况下,它
状态A(IO B)
它进入这里,我们可以看到必须在不做IO的情况下生成新状态!这是一项迫使新状态和IO效应完全分离的计算。它实际上表现得好像我们有两个单独的功能
一样,这不是您真正想要的。这可能就像
允许在IO完成后生成新状态一样。
要获得该类型,您无法嵌套单子,但是您需要一个单调的变形金刚
statet
:这是 a monad。您可能需要使用
lift
或liftio
将IO操作转换为此类类型,但应按需要行为。Monad do not compose, in general. I think you are being bit by this.
In general, if
m
andn
are monads, we can not writem (n a)
for a monadic action that mixes the features ofm
andn
. In general, it could even fail to be a monad.In your case, you are using something like
State A (IO B)
hoping to be able to access the state of typeA
and still doIO
, but that's not the case.Indeed, by definition we have (up to some wrappers):
which in your case
State A (IO B)
it becomesHere, we can see that the new state must be generated without doing IO at all! This is a computation which forces the new state and the IO effects to be completely separated. It effectively behaves as if we had two separate functions
Likely, that's not what you actually want. That is probably something like
allowing the new state to be generated after IO is done.
To obtain that type, you can not nest monads, but you need a monad transformer like
StateT
:This is a monad. You will probably need to use
lift
orliftIO
to convert IO actions to this type, but it should behave as desired.