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{x
do
-块不是语句,它们是值。你认为这应该做什么?就像我在上一个问题中说的,请在使用单子之前先研究单子!要处理缩进,可以使用
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) }