Haskell where子句下的Do语句
我正在尝试使用Haskell where子句下的Do语句,haskell,scope,functional-programming,monads,do-notation,Haskell,Scope,Functional Programming,Monads,Do Notation,我正在尝试使用IO[[String]]将IO[String]转换为[String] 解压块 |words'/=[]=block:(decompEventBlocks.drop$(长度块)words') |否则=[] 哪里 做 无法将IO字符串转换为字符串 然而,您可以做的是将IO字符串的内容绑定到一个“变量”,但这仍然会导致整个计算嵌入IO中 foo = do x <- baz -- here baz is the IO String let x' = doStuff x
IO[[String]]将IO[String]
转换为[String]
解压块
|words'/=[]=block:(decompEventBlocks.drop$(长度块)words')
|否则=[]
哪里
做
无法将IO字符串转换为字符串
然而,您可以做的是将IO字符串的内容绑定到一个“变量”,但这仍然会导致整个计算嵌入IO中
foo = do
x <- baz -- here baz is the IO String
let x' = doStuff x
return x' -- embeds the String inside IO, as otherwise the computation would result in IO ()
foo=do
x记住:do
-块用于一元表示法。这意味着以下内容适用:
do {a; b} = a >> b
dp {a <- b; c} = b >>= \a -> c
为了了解单子,do
-表示法,>=
和>
,我强烈建议在尝试更多的单子代码之前,先阅读以获得良好的理解。作为对AJFarmar回答的一个稍微不同的角度:在中,你能拥有的唯一东西是声明<代码>执行
块不是声明,它们是表达式。也就是说,这与您尝试编写where 2+5
相同。如果要在中声明块
,则必须
Do符号用于编写一般形式的表达式
ex :: Monad m => m t
let ex = do
{ x <- foo -- foo :: Monad m => m a, x :: a
; y <- bar x -- bar x :: Monad m => m b, y :: b
; z <- baz x y -- baz x y :: Monad m => m c, z :: c
; quux x y z -- quux x y z :: Monad m => m t
}
所有的Monad m=>ma
表达式都是that,表达式,因此特别可以是if-then-else
表达式,其结果分支和替代分支都是相同的一元类型(这对于初学者来说常常是混淆的):
do{xdo
-块不是语句,它们是值。你认为这应该做什么?就像我在上一个问题中说的,请在使用单子之前先研究单子!要处理缩进,可以使用do{x;y;z}
显式语法。将函数更改为[String]>[[String]]
然后使用fmap
将其提升到IO
单子中。@onurcanbektas单子不是“语言的内部工作机制”,它们是定义其I/O约束的Haskell的一个重要特性。如果不理解单子,你将无法写出好的Haskell。了解单子!@AJFarmar虽然正确,但确实如此符号可以自己掌握,就像DSL一样,只需遵循很少的规则。这可能是掌握的第一步,也可能是更小的一步。(此外,包括所有可选的括号、大括号和分号(do、case、$,…),通过消除语法中可能存在的任何额外不确定性,可以真正帮助初学者)。我只是直接复制粘贴代码,但它会抛出2个错误,因为(:)它应该是[String],而不是IO[String];这至少是ghci所说的。啊,这是一个缺陷,因为原始定义现在更新。(现在更新)但仍然是rest中decompEventBlocks的参数顺便说一句,代码给出了错误(这就是我上面问题的原因。)@onurcanbektas我在逐字运行此代码时没有收到错误。如果您收到错误,请找到导致错误的代码并在其他地方发布另一个问题。因此,words'@onurcanbektas因为words'>=\words'->b
。我在回答中解释了这一点。
do {a; b} = a >> b
dp {a <- b; c} = b >>= \a -> c
decompEventBlocks :: IO [String] -> IO [[String]]
decompEventBlocks words = do
-- We unwrap the IO [String], but we keep it in the do-block,
-- because it must be kept in a monadic context!
words' <- words
let block = (takeWhile (/="END") words')
-- This is equivalent to the guards you had in your function.
-- NB return :: Monad m => a -> m a, to keep it in a monadic context!
if not $ null words'
then do
-- Since the recursion is monadic, we must bind it too:
rest <- decompEventBlocks $ return $ drop (length block) words'
return $ block : rest
else return []
where
// can have other declarations, even mutually recursive
block = ...
ex :: Monad m => m t
let ex = do
{ x <- foo -- foo :: Monad m => m a, x :: a
; y <- bar x -- bar x :: Monad m => m b, y :: b
; z <- baz x y -- baz x y :: Monad m => m c, z :: c
; quux x y z -- quux x y z :: Monad m => m t
}
do { _ <- p ; _ <- q ; r } === do { p ; q ; r }
do { x <- p ; return x } === do { p } === p
do { x <- return v ; foo x } === do { foo v } === foo v
do { p ; q ; r } === do { p ; do { q ; r } }
=== do { do { p ; q } ; r }
do { x <- p ; === do { x <- p ;
y <- q x ; z <- do { y <- q x ;
return (foo x y) } return (foo x y) } ;
return z }
do { x <- p ;
y <- if (pred x) then (foo x) else (bar x) ;
return (baz x y) }