let式で一行に複数束縛を書くときの区切り文字

個人的備忘録

なんとなく、連続した数字の有限のリストから素数をとりだすエラトネスのふるいを作りたくなって、ghciを立ち上げてつくってみた。
最初、

let fact (x:xs) = x : fact [ y | y <- xs , 0 /= ( y `mod` x ) ]

な感じで、定義したんだけど、よく考えるとこれ、最後に[]が来たときにアウトになる。まぁ、

take 10 $fact [2..100]

のように、リストに存在する個数より少ない個数を取り出すようにしてあげれば、遅延評価のおかげで救われるのですが、なんとなく汚い。

かといって、ghci上ではパターンマッチをつかっての関数定義ができないわけで、

Prelude> let fact [] = []
fact :: [t] -> [a]
Prelude> let fact (x:xs) = x : fact [ y | y <- xs , 0 /= ( y `mod` x ) ]
fact :: (Integral t) => [t] -> [t]
Prelude> fact [ 2 .. 10 ]
[2,3,5,7*** Exception: <interactive>:1:4-62: Non-exhaustive patterns in function fact

let式で定義しているからしょうがないんだけど。

というわけで、普段Haskellで僕はあまりつかわない(というか、最近Haskell自体ほとんどさわれてませんでしたが)if式
を使うことに。

とりあえず、

fact xs = if xs == [] then [] else (head xs ) : fact [ y | y <- (tail xs) , 0 /= ( y `mod` (head xs)) ]

とかでできるんだけど、毎回head とかtailを書くのは面倒。

というわけで、let式の再登場なわけなんですが、今回は1行に複数束縛したい。通常、

let 変数 = 値
    変数 = 値
    in
       式

みたいに複数行で書くので、何がデリミタになるのかなぁと思ったら、セミコロン(;)でした。
というわけで、

Prelude> let fact s = if s == [] then [] else let x = head s ; xs = tail s in x  : fact [ y | y <- xs , 0 /= ( y `mod` x ) ]
fact :: (Integral a) => [a] -> [a]
Prelude> fact [2..40]
[2,3,5,7,11,13,17,19,23,29,31,37]
it :: [Integer]