読者です 読者をやめる 読者になる 読者になる

by shigemk2

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

let

Haskell

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)