「ふつうのHaskellプログラミング」読みます(5)

6章。基本的な値と、それらまわりの関数とか。

6.2 真偽値
Prelude> not True
False
Prelude> not True && False
False
Prelude> False || True
True

まあふつう。

6.3 数値

Haskellの整数型はInt、Integer。Intが上限下限ありの整数、Integerが制限無しの整数型。rubyでいうとIntがFixnumでIntegerがBignumみたいな。あと数値リテラルは文脈に合わせて適当な数値型になるらしいです。

Prelude> 9999999999999999999999999999999999999
9999999999999999999999999999999999999
Prelude> 9999999999999999999999999999999999999 :: Int
-1

8進数と16進数リテラルあり。

Prelude> 0o11
9
Prelude> 0x11
17

浮動小数点型にはFloatとDoubleあり。

Prelude> 2 :: Double
2.0
Prelude> 11e+4
110000.0
Prelude> 99999999999999999999999999999999999999999999999999 :: Float
Infinity
Prelude> 99999999999999999999999999999999999999999999999999 :: Double
1.0e50

色々な演算あります。詳しくはdoc/libraries/base/Prelude.htmlとか読めばいいと思う。

Prelude> div 33 7
4
Prelude> mod 33 7
5
Prelude> -88
-88
Prelude> -(88 -80)
-8
Prelude> abs $ -8
8
Prelude> floor 3.33
3
Prelude> ceiling 3.33
4

6.4 文字と文字列

文字列は文字のリスト。doc/libraries/haskell98/Char.htmlあたり読むと関数がいろいろのってる。

Prelude Char> isUpper 'a'
False
Prelude Char> isAlpha 'a'
True
Prelude Char> isUpper 'a'
False
Prelude Char> isHexDigit 'a'
True
Prelude Char> isDigit 'a'
False
Prelude Char> chr 90
'Z'
Prelude Char> ord 'a'
97
Prelude Char> map ord "hogehoge"
[104,111,103,101,104,111,103,101]

6.5 タプル

これもOCamlとかでよく使うし知っていた。

Prelude> (3, 2)
(3,2)
Prelude> fst (3, 2)
3
Prelude> snd (3, 2)
2
Prelude> zip [1, 2, 3, 4, 5] [9, 8, 7]
[(1,9),(2,8),(3,7)]
Prelude> unzip $ zip [1, 2, 3, 4, 5] [9, 8, 7]
([1,2,3],[9,8,7])

これって(1, 2, 3, 4)とかどうすんだ。パターンマッチで取れつうことか。

6.6 リスト

Schemeとかでさんざん使ったぞ。

Prelude> 1 : 2 : 3 : 4 : []
[1,2,3,4]
Prelude> let cons = (:)
Prelude> (cons 1 (cons 2 (cons 3 (cons 4 []))))
[1,2,3,4]

やったね! まあそれはいいとして。便利な数列表記なるものあったらしいです。

Prelude> [1..8]
[1,2,3,4,5,6,7,8]
Prelude> [1, 3..8]
[1,3,5,7]
Prelude> [1,2..8]
[1,2,3,4,5,6,7,8]
Prelude> [1,2,3..8]
<interactive>:1:6: parse error on input `..'

null, ++といった関数あるよと。

Prelude> null []
True
Prelude> null [1]
False
Prelude> [] ++ [1]
[1]
Prelude> [1,2] ++ [1]
[1,2,1]

内包表記もあります。

Prelude> [abs x | x <- [-10..10]]
[10,9,8,7,6,5,4,3,2,1,0,1,2,3,4,5,6,7,8,9,10]
Prelude> [x+3 | x <- [0..10]]
[3,4,5,6,7,8,9,10,11,12,13]
Prelude> [(x,y) | x <- [1,2], y <- ['a'..'c']]
[(1,'a'),(1,'b'),(1,'c'),(2,'a'),(2,'b'),(2,'c')]
Prelude> [x*y | x <- [1..5], y <- [1..3]]
[1,2,3,2,4,6,3,6,9,4,8,12,5,10,15]

6.7 実習

catn.hs
main = do cs <- getContents
          putStr (numbering cs)
numbering cs = unlines (map format (zipLineNumber (lines cs)))
zipLineNumber xs = zip [1..]  xs
format (n, line) = rjust 6 (show n) ++ " " ++ line
rjust width s = replicate (width - length s) ' ' ++ s

無限リストとか便利ですねえ。うーん、型は型推論に丸投げってのは楽だけど、まずいかも。読むときにはこっちが型推論する必要性が生まれてくる。

% ghc catn.hs -o catn
% ./catn </usr/include/stdio.h
     1 /* Define ISO C stdio on top of C++ iostreams.
...
   915
   916 #endif /* !_STDIO_H */

こうなるわけです。

6.9 練習問題

たのしいフェーズ。と思ったらプログラム書く方の問題じゃなかった。

resolve f (x:xs) = ((++) (textify x) (resolve f xs))
getenv key env = (($) (fromMaybe "") (lookup key env))
readTemplate id = (($) readFile ((++) (prefix repo) ((++) "/" id)))

ついカッとなってLispみたいにしてやった。合ってんのかこれ。まあたぶん。

test