21

Haskell の

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どちらにも対応しないステートメントを持っていることがよくあります。たとえば、Parsec を使用して文字列から何かを解析する Pandoc のコードを次に示します。<-=

-- | 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 strsetInput oldInput、およびsetPosition oldPosを Scalaに変換する方法を一生理解できません。意味のない変数を入れるだけでうまくいくと思いますので、次<-のように使用できます

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

しかし、それが正しいかどうかはわかりません。もしそれが正しければ、これを行うためのより良い方法があるに違いないと確信しています。

ああ、この質問に答えられるなら、もう 1 つ答えてもらえますか: モナドがブラック マジックのように感じられなくなるまで、どれくらいモナドを見つめていなければなりませんか? :-)

ありがとう!トッド

4

1 に答える 1

28

はい、その翻訳は有効です。

do { x <- m; n }と同等m >>= \x -> nであり、 とdo { m; n }同等m >> nです。m >> nm >>= \_ -> n(where_は「この値を何にもバインドしない」ことを意味する) と定義されているため、実際には有効な翻訳です。、またはdo { m; n }と同じです。do { _ <- m; n }do { unusedVariable <- m; n }

ブロック内の変数バインディングのないステートメントはdo、通常、意味のある結果がないため、単純に結果を無視します。たとえば、 の結果を処理することは何も興味深いことでputStrLn "Hello, world!"はないため、その結果を変数にバインドしません。

(モナドが黒魔術であることに関しては、モナドはまったく複雑ではないということを理解するのが最善です。モナドのより深い意味を見つけようとすることは、一般に、モナドがどのように機能するかを学ぶ生産的な方法ではありません。モナドは単なるインターフェースです。 Haskell の抽象型クラスをしっかりと理解するには、 Typeclassopediaを読むことをお勧めしますが、それを十分に理解するには、一般的な Haskell 入門を読む必要があります)。

于 2012-05-04T01:45:28.433 に答える