Вопрос по haskell – Скала эквивалент Do-нотации Хаскелла (еще раз)

19

Я знаю, что на Хаскелле

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 в Скала. Я думаю, что это будет работать, если я просто добавлю бессмысленные переменные, чтобы я мог использовать<-, лайк

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

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

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

Спасибо! Тодд

Я предполагаю, что это самый подобный Scala способ сделать это. TOB
Не уверен, что это действительно будет возможно, но это может выглядеть более естественным, если переместить эти утверждения в тело for, где вы действительно можете использовать процедурный стиль. dividebyzero
Если вы не планируете использовать переменную, вы можете заменить ее имя на подчеркивание:_ <- setInput str incrop

Ваш Ответ

1   ответ
25

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, хотя вам нужно прочитать общее введение в Haskell, чтобы извлечь из этого немало пользы.)

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded>>?
Error: User Rate Limit Exceeded>>Error: User Rate Limit Exceededfor { _ <- M }

Похожие вопросы