LINUX.ORG.RU

Подскажите монаду

 , monads, ,


0

7

Всем привет.

Подскажите монаду, которая, как Maybe/Option позволяет early termination, но при этом возвращает не Nothing или None, а то, что удалось накопить so far. Возможно, это комбинация State с чем-то ещё. Нужно сделать парсер для нестрогой грамматики: парсим, как можем, а на EOF возвращаем, что получилось распарсить. Интересует что-то из Scalaz, если можно воспользоваться готовым, но варианты на Haskell тоже приветствуются. Важна сама идея.

★★★★
Ответ на: комментарий от qnikst
import Control.Monad.Trans.Either
import "mtl" Control.Monad.State
import Data.DList (DList)
import qualified Data.DList as DL

data Q = Q Int deriving Show

type M a b = EitherT a (State (DList Q)) b

l :: Q -> M a ()
l y = lift $ modify (\x -> x `DL.snoc` y)

e :: a -> M a ()
e x = left x

test1 = do
  l (Q 1)
  l (Q 2)
  e ()
  l (Q 3)
λ> fst $ runState (runEitherT test1) DL.empty
Left ()
λ> DL.toList . snd $ runState (runEitherT test1) DL.empty
[Q 1,Q 2]

хотя я бы делал по другому..

qnikst ★★★★★
()
Последнее исправление: qnikst (всего исправлений: 1)
Ответ на: комментарий от true_admin

а черт знает :) надо подумать, просто монадный стек городить не стал бы сразу.

qnikst ★★★★★
()

Как ты себе это представляешь?

Если early termination, то копить нечего; если копить вместо фейла, то где early termination?

А так Alternative/MonadPlus для EitherT использует Monoid e.

anonymous
()
Ответ на: комментарий от anonymous

Если early termination, то копить нечего; если копить вместо фейла, то где early termination?

Грамматика не строгая, то есть я могу ожидать какие-то секции в структуре, но их может не оказаться, поэтому на EOF надо вернуть то, что получилось достать - это и есть early termination.

readHeader
readSection1
readSection2
// oops no section 3, return what we have so far
readSection3

При этом input хочется чейнить неявно, через State.

Bohtvaroh ★★★★
() автор топика
Последнее исправление: Bohtvaroh (всего исправлений: 2)

Тебе видимо нужна монада AbortT.

KblCb ★★★★★
()
Ответ на: комментарий от Miguel

Со State я могу кусочки парсера для отдельных секций представлять функциями вида s -> (a, s), и это удобно, а с врайтером я не понимаю, как это будет выглядеть, и получится ли аналогично структурировать.

Bohtvaroh ★★★★
() автор топика
Ответ на: комментарий от Miguel

Со StateT получается что-то вроде:

import scalaz._
import Scalaz._

object Playground extends App {
  type Stream = String
  type Mined = List[String]
  type ParserState = (Stream, Mined)

  type MyEither[+T] = Either[Playground.ParserState, T]

  val s1 = StateT[MyEither, ParserState, Unit] { s =>
    Right((("input at s1", add(s, "header")), ()))
  }
  val s2 = StateT[MyEither, ParserState, Unit] { s =>
    Right((("input at s2", add(s, "section1")), ()))
  }
  val s3 = StateT[MyEither, ParserState, Unit] { s =>
    Left(s)
  }
  val s4 = StateT[MyEither, ParserState, Unit] { s =>
    Right((("input at s4", add(s, "section3")), ()))
  }

  def add(s: ParserState, mined: String): Mined = mined :: s._2

  val parser =
    for {
      _ <- s1
      _ <- s2
      _ <- s3
      _ <- s4
    } yield ()
  println(parser.run(("input", List())))
}
Left((input at s2,List(section1, header)))

Пока не понял, нравится мне, или нет.

Bohtvaroh ★★★★
() автор топика
Последнее исправление: Bohtvaroh (всего исправлений: 1)
Ответ на: комментарий от true_admin

Пока что не писал, но если позитивное что-то получится, напишу сюда.

Bohtvaroh ★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.