1. ホーム
  2. haskell

Haskellでは、letと一緒にinをいつ使うのか?

2023-08-25 08:12:23

質問

次のコードでは、最後のフレーズに in を付けることができます。それは何かを変更しますか?

もう一つ質問です。もし私が in をつけた場合、インデントする必要があるのでしょうか?

私はインデントせずに試してみましたが、hugsは文句を言います。

do {...} の最後のジェネレータは式である必要があります。

import Data.Char
groupsOf _ [] = []
groupsOf n xs = 
    take n xs : groupsOf n ( tail xs )

problem_8 x = maximum . map product . groupsOf 5 $ x
main = do t <- readFile "p8.log" 
          let digits = map digitToInt $concat $ lines t
          print $ problem_8 digits


編集

なるほど、みんな私が言っていることを理解していないようですね。言い直します。 上記の文脈からすると、次の2つは同じものでしょうか?

1.

let digits = map digitToInt $concat $ lines t
print $ problem_8 digits

2.

let digits = map digitToInt $concat $ lines t
in print $ problem_8 digits

で宣言されたバインディングのスコープに関するもう一つの質問です。 let : 私は ここで というのを。

where 句のことです。

時には、いくつかのガードされた方程式にバインディングをスコープするのが便利で、それにはwhere節が必要です。

f x y  |  y>z           =  ...
       |  y==z          =  ...
       |  y<z           =  ...
     where z = x*x

これはlet式ではできないことに注意してください。 を包含する .

私の質問:だから、変数の数字は、最後の印刷フレーズに表示されていないはずです。私はここで何かを見逃していますか?

どのように解決するには?

短い答え : 使用する let を使わずに in は、Do-block の本文中、および | の後の部分で、リスト内包で それ以外の場所では let ... in ... .


キーワード let はHaskellでは3つの方法で使用されます。

  1. 最初の形式は レット式 .

    let variable = expression in expression
    
    

    これは、式が許されるところならどこでも使えるもので、例えば

    > (let x = 2 in x*2) + 3
    7
    
    
  2. 2つ目は let-ステートメント . この形式は、do-notation の内部でのみ使用されます。 in .

    do statements
       let variable = expression
       statements
    
    
  3. 3番目は2番目と同様で、リスト内包の内部で使用されます。ここでも in .

    > [(x, y) | x <- [1..3], let y = 2*x]
    [(1,2),(2,4),(3,6)]
    
    

    この形式は、後続のジェネレータや、の前の式でスコープ内にある変数を束縛します。 | .


ここであなたが混乱している理由は、(正しい型の)式はdo-block内の文として使用することができるからです。 let .. in .. は単なる式だからです。

haskellのインデントルールにより、前の行よりさらにインデントされた行は前の行の続きであることを意味するので、この

do let x = 42 in
     foo

としてパースされます。

do (let x = 42 in foo)

インデントがないと、パースエラーになります。

do (let x = 42 in)
   foo

結論から言うと、決して in をリスト内包やDOブロックの中で使ってはいけません。これらのコンストラクトはすでに独自の形式の let .