Scala эквивалент Haskell do-notation (еще раз) - программирование
Подтвердить что ты не робот

Scala эквивалент Haskell do-notation (еще раз)

Я знаю, что Haskell's

do
  x <- [1, 2, 3]
  y <- [7, 8, 9]
  let z = (x + y)
  return z

может быть выражена в Scala как

for {
  x <- List(1, 2, 3)
  y <- List(7, 8, 9)
  z = x + y
} yield z

Но, особенно с монадами, Haskell часто имеет инструкции внутри блока do, которые не соответствуют либо <-, либо =. Например, вот какой-то код из Pandoc, который использует Parsec для анализа чего-то из строки.

-- | Parse contents of 'str' using 'parser' and return result.
parseFromString :: GenParser tok st a -> [tok] -> GenParser tok st a
parseFromString parser str = do
  oldPos <- getPosition
  oldInput <- getInput
  setInput str
  result <- parser
  setInput oldInput
  setPosition oldPos
  return result

Как вы можете видеть, он сохраняет позицию и ввод, запускает синтаксический анализатор строки, а затем восстанавливает ввод и позицию перед возвратом результата.

Я не могу за всю жизнь понять, как перевести setInput str, setInput oldInput и setPosition oldPos в Scala. Я думаю, что это сработает, если я просто поместил бессмысленные переменные, чтобы использовать <-, например

for {
  oldPos <- getPosition
  oldInput <- getInput
  whyAmIHere <- setInput str
  result <- parser
  ...
} yield result

но я не уверен, что случай, и если это правильно, я уверен, что должен быть лучший способ сделать это.

О, и если вы можете ответить на этот вопрос, можете ли вы ответить на еще один вопрос: как долго мне нужно смотреть на Монады, прежде чем они не будут чувствовать себя черной магией?: -)

Спасибо! Todd

4b9b3361

Ответ 1

Да, этот перевод действителен.

do { x <- m; n } эквивалентен m >>= \x -> n, а do { m; n } эквивалентен m >> n. Поскольку m >> n определяется как m >>= \_ -> n (где _ означает "не привязывать это значение ко всему" ), это действительно действительный перевод; do { m; n } совпадает с do { _ <- m; n } или do { unusedVariable <- m; n }.

Оператор без привязки переменной в блоке do просто игнорирует результат, как правило, потому что нет значимого результата. Например, нет ничего интересного в результате результата putStrLn "Hello, world!", поэтому вы не привязывали бы его результат к переменной.

(Что касается монад, являющихся черной магией, то лучшая реализация, которую вы можете иметь, заключается в том, что они не очень сложны вообще, а попытка найти более глубокий смысл в них обычно не является продуктивным способом изучения того, как они работают. просто интерфейс для составления вычислений, которые особенно распространены. Я рекомендую прочитать Typeclassopedia, чтобы получить четкое представление о абстрактных классах Haskell, хотя вам нужно будет прочитали общее введение Хаскелла, чтобы получить от него много чего.)