Делать заявление под пунктом где - PullRequest
0 голосов
/ 11 июня 2018

Я пытаюсь преобразовать IO [String] в [String] с привязкой <-;однако мне нужно использовать блок do, чтобы сделать это в операторе where, но Haskell постоянно жалуется на отступ.Вот код:

decompEventBlocks :: IO [String] -> IO [[String]]
decompEventBlocks words
 | words' /= [] = block : (decompEventBlocks . drop $ (length block) words')
 | otherwise = []
  where 
   do
    words' <- words
    let block = (takeWhile (/="END") words')

В чем причина?И как мы можем использовать блок do в операторе where?Более того, есть ли шанс, что мы сможем выступить с заявлениями перед охранниками?

Ответы [ 4 ]

0 голосов
/ 12 июня 2018

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
          }

Обратите внимание, что все m одинаковы, а a, b, c, ... могут отличаться, хотя t в последнем типе подвыражения do и общий тип выражения do одинаковы.

Переменные do называются "связанными" с помощью конструкции <-.Они входят в область действия при введении (слева от <-) и остаются в области действия для всех последующих подвыражений do .

Одно встроенное монадическое выражение, доступное для любогомонада return :: Monad m => a -> m a.Таким образом, x <- return v связывает x с v, так что x будет доступно в последующих подвыражениях и будет иметь значение v.

Все переменные do ограничены этим do блоком, и не может использоваться вне его.Область действия каждой переменной - это весь код в одном и том же блоке do ниже / после привязки переменной.

Это также означает, что <- является нерекурсивным связыванием, поскольку переменная не может идти как с правой, так и с левой стороны: это будет два разных в этом случае переменные с одинаковыми именами и переменная справа должны быть установлены где-то выше этой точки.

Здесь есть несколько общих закономерностей:

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 }

* * * * * * * * * * * * * * * Все выражения Monad m => m a, в частности, выражения и, в частности, могут быть if - then - else выражениями, причем как последовательные, так и альтернативные ветви имеют одинаковый монадический тип (что часто вводит в заблуждение начинающих):

    do { x <- p ;
         y <- if (pred x) then (foo x) else (bar x) ;
         return (baz x y) }

обновление: Одним из главных моментов монады является ее полное отделение эффектов от чистых вычислений.Однажды в монаде вы не можете "выйти" .Монадические вычисления могут использовать чистые вычисления, но не наоборот.

0 голосов
/ 11 июня 2018

Помните: do -блоки синтаксический сахар для монадической записи.Это означает, что применимо следующее:

do {a; b} = a >> b
dp {a <- b; c} = b >>= \a -> c

Другими словами, при использовании примечания do вы фактически производите значения.Вот почему вы не можете просто иметь do -блок на верхнем уровне вашего where заявления.

Чтобы решить эту проблему, нужно поместить функцию в do -блок:

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 []

Чтобы узнать о монадах, do -обозначении, >>= и >>, я настоятельно рекомендую прочитать главы LYAH , чтобы получить хорошее понимание, прежде чем пытаться использовать более монадический код.

0 голосов
/ 12 июня 2018

Как немного другой угол в ответе А.Дж.Фармара: в where есть только объявления.do блоки не являются объявлениями, они являются выражениями.Т.е. это так же, как если бы вы пытались написать where 2+5.Если вы хотите объявить block в where, должно быть

where
  // can have other declarations, even mutually recursive
  block = ...
0 голосов
/ 11 июня 2018

Вы не можете преобразовать для строки ввода-вывода в строку.

Однако вы можете привязать содержимое строки ввода-вывода к переменной, но это все равно приведет кво всех вычислениях, встроенных в 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 x = baz x -- x here is your 'IO String'
  where
    baz x = do
      x' <- x
      return $ doStuff x'
...