by shigemk2

当面は技術的なことしか書かない

let

let 式は where 節にとてもよく似ている。
where は関数の終わりで変数を束縛し、
その変数はガードを含む関数全体から見える。

それに対し、let式は、どこでも変数を束縛でき、そしてlet自身も式になる。

しかし let 式が作る束縛は局所的で、ガード間で共有されない。
束縛を行う Haskell の他の構文と同じく、let 式のパターンマッチも使える。

letは、
let bindings in expression という形を取る。

束縛を先に書いて、inのあとに式を追加するという感じ。

ただし、letは式だけどwhereは式じゃないことに留意すること。

cylinder :: Double -> Double -> Double
cylinder r h =
  let sideArea = 2 * pi * r * h
      topArea = pi * r ^ 2
                in sideArea + 2 * topArea
Main> cylinder 3.0 4.0
131.94689145077132

Main> 4 * (let a = 9 in a + 1) + 2
42

# ローカルスコープに関数を作ることも出来る
Main> [let square x = x * x in (square 5, square 3, square 2)]
[(25,9,4)]

# 複数の変数を1行で束縛するときは ; を使う
Main> (let a = 100; b = 200; c = 300 in a*b*c, let foo="Hey "; bar = "there!" in foo ++ bar)
(6000000,"Hey there!")

# タプルを分解するのにもletは使え、式全体が値 a + b + cを有する
Main> (let (a, b, c) = (1, 2, 3) in a+b+c) * 100
600
--リスト内包表記でもletは使える。ここでは、フィルタ内で、名前を束縛している。
--ここでいう (w, h) <- xs はジェネレータと呼ばれ、変数bmiはジェネレータからは参照できない
--理由はletの束縛よりも前に定義されているから
calcBmis' :: [(Double, Double)] -> [Double]
calcBmis' xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2]

calcBmis'' :: [(Double, Double)] -> [Double]
calcBmis'' xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi > 25.0]
Main> calcBmis' [(3, 2)]
[0.75]
Main> calcBmis'' [(3, 2)]
[]
Main> calcBmis'' [(100, 50)]
[]
Main> calcBmis'' [(100, 2)]
[100.0]
Main> calcBmis'' [(100, 1.25)]
[64.0]
# なお、letのinは省略できる。こうすると、後のセッションでもletで束縛した変数を後で使える
Main> let zoot x y z = x * y * z
Main> zoot 3 9 2
54
Main> let boot x y z = x * y + z in boot 3 4 2
14
# in部分が省略されていないlet式は、それ自体が値を表す式である。
Main> boot 

<interactive>:131:1:
    Not in scope: `boot'
    Perhaps you meant `zoot' (line 128)