15

Haskellでは、do-block内で「in」と「let」を使用しないのはなぜですか?

たとえば、以下のやや不自然な例では、次のようになります。

afunc :: Int -> Int
afunc a = 
       let x = 9 in
       a * x

amfunc :: IO Int -> IO Int
amfunc a = do
       let x = 9
       a' <- a
       return (a' * x)

覚えるのは簡単なルールですが、その理由がわかりません。

4

3 に答える 3

15

との両方を定義する式を提供していafuncますamfunc。Let-expressionsとdo-blocksはどちらも式です。ただし、let-expressionは、「in」キーワードの後に​​指定された式をスコープとする新しいバインディングを導入しますが、do-blockは式で構成されていません。これは、一連のステートメントです。do-blockには、次の3つの形式のステートメントがあります。

  1. 結果がいくつかの変数xにバインドされている計算。

    x <- getChar
    
  2. 次のように、結果が無視される計算

    putStrLn "hello"
    
  3. のように、letステートメント

    let x = 3 + 5
    

letステートメントは、let式と同じように、新しいバインディングを導入します。この新しいバインディングの範囲は、do-blockの残りのすべてのステートメントに拡張されます。

つまり、let式の「in」の後に続くのは式ですが、let式の後に続くのは一連のステートメントです。もちろん、let-expressionを使用して特定のステートメントの計算を表現することはできますが、バインディングの範囲は、そのステートメントを超えて後続のステートメントに拡張されることはありません。検討:

do putStrLn "hello"
   let x = 3 + 5 in putStrLn "eight"
   putStrLn (show x)

上記のコードにより、GHCで次のエラーメッセージが表示されます。

Not in scope: `x'

一方

do putStrLn "hello"
   let x = 3 + 5
   putStrLn "eight"
   putStrLn (show x)

正常に動作します。

于 2012-07-26T18:10:53.027 に答える
9

あなたは確かlet .. inにdo-notationで使うことができます。実際、Haskell Reportによると、次のようになっています。

do {let decls; stmts}

脱糖

decls indo{stmts}をしましょう

そうでなければ、「in」ブロックの深いインデントまたは区切りが必要になる可能性があるため、便利だと思います。これは、in..からdo-blockの最後までです。

于 2012-07-26T17:54:03.263 に答える
6

簡単に言えば、Haskelldoブロックは面白いということです。Haskellは式ベースの言語です。ブロックdoのポイントdoはある種の「ステートメント」構文を提供することであるため、ブロックを除きます。ほとんどの「ステートメント」はタイプの表現にすぎMonad m => m aませんが、言語の他のどの構文にも対応しない2つの構文があります。

  1. <-アクションの結果を:でバインドすることはx <- action「ステートメント」ですが、式ではありません。この構文にはとが必要x :: aですaction :: Monad m => m a
  2. in-lessバリアントはlet、代入ステートメントに似ています(ただし、右側の純粋なコード用です)。では、それはとlet x = exprの場合でなければなりません。x :: aexpr :: a

の使用を<-脱糖できるのと同じように(この場合、>>=ラムダに)、- inlessletは常に通常の糖に脱糖できることに注意してlet ... in ...ください:

do { let x = blah; ... }
    => let x = blah in do { ... }
于 2012-07-26T20:04:03.057 に答える