by shigemk2

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

第2期 第1回 H本読書会 in 秋葉原 #readhbon

Haskellはおもしろい

http://readhbon.doorkeeper.jp/events/16706

Haskellは変な言語

IRCチャンネルがある

Haskellは純粋関数型言語

コンピュータにナニをするかは伝えず、なんであるかを伝える=関数

  • 束縛(一度定義した変数の値を変更は出来ない)
  • 遅延評価
  • 副作用がない
  • リストは要求があったときに一度だけ走査される
  • Haskellは静的型づけ言語
  • コンパイラがエラーをチェックする
  • 型推論

あと、Haskellは簡潔にコードを書くことが出来る

Haskellの世界に飛び込むのに必要なもの

コンパイラはGHC 対話モードつき

話の空中戦はつらいよ

第1章 はじめの第一歩

ghciを起動してみる

➜  ~  ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :set prompt "ghci> "
ghci> 

軽い演算

ghci> 2 + 5
7
ghci> 49 * 100
4900
ghci> 1892 - 1472
420
ghci> 5 / 2
2.5
ghci> (50 * 100) - 4999
1
ghci> 50 * 100 - 4999
1
ghci> 50 * (100 - 4999)
-244950
ghci> 5 * -3

<interactive>:10:1:
    Precedence parsing error
        cannot mix `*' [infixl 7] and prefix `-' [infixl 6] in the same infix expression
ghci> 5 * (-3)
-15
ghci> True && False
False
ghci> True && True
True
ghci> "hello" == "hello"
True
ghci> 5 /= 4
True
ghci> 5 /= 5
False

1.1 関数呼び出し

上の例は中置関数。

これからの例は前置関数

ghci> succ 8
9
ghci> min 9 10
9
ghci> min 3.4 3.2
3.2
ghci> min 100 101
100
ghci> max 100 101
101

中置関数と前置関数の組み合わせ

ghci> succ 9 * 10
100
ghci> succ (9 * 10)
91

バッククオートで中置関数

ghci> 92 `div` 10
9

1.2 赤ちゃんの最初の関数

doubleMe x = x + x
doubleMe x = x + x

main = do
  print $ doubleMe 2
doubleMe x = x + x
doubleUs x y = doubleMe x + doubleMe y

main = do
  print $ doubleUs 4 9
  • 明らかに正しい関数を組み合わせて、より大きな関数を組み立てる
  • すべての関数はなにかを返さなければならない
  • Haskellのifは必ず値を返す式であって、文ではない

1.3 リスト入門

  • いちようなデータ構造
  • 同じ型の要素を複数個格納できる
  • 違う型の要素を格納することはできない

連結

ghci> let lostNumbers = [4,8,15,16,23,42]
ghci> lostNumbers
[4,8,15,16,23,42]

(文字列は文字のリスト)

  • ++は連結
  • :はcons演算子で、リストの先頭に何かを追加するヤツ
ghci> "hello " ++ "world" 
"hello world"
ghci> 5:[6,7,8,9]
[5,6,7,8,9]
ghci> [6,7,8,9] ++ 5
-- エラー!!

アクセス

  • !!を使う
ghci> "Steve Buscemi" !! 6
'B'

リストの中のリスト

リストのなかにリストを含むことが出来る

リストの比較

リスト同士の比較も可能

ghci> [3,2,1] > [2,1,0]
True
ghci> [3,2,1] > [4,1,0]
False

リスト操作

  • head
  • tail
  • last
  • init など
ghci> head [5,4,3,2,1]
5
ghci> tail [5,4,3,2,1]
[4,3,2,1]
ghci> last [5,4,3,2,1]
1
ghci> init [5,4,3,2,1]
[5,4,3,2]
ghci> head []
*** Exception: Prelude.head: empty list
ghci> length [5,4,3,2,1]
5
ghci> null [5,4,3,2,1]
False
ghci> reverse [5,4,3,2,1]
[1,2,3,4,5]
ghci> take 3 [5,4,3,2,1]
[5,4,3]
ghci> take 1 [5,4,3,2,1]
[5]
ghci> take 99 [5,4,3,2,1]
[5,4,3,2,1]
ghci> take 0 [5,4,3,2,1]
[]
ghci> drop 0 [5,4,3,2,1]
[5,4,3,2,1]
ghci> drop 3 [5,4,3,2,1]
[2,1]
ghci> drop 100 [5,4,3,2,1]
[]
ghci> maximum [5,4,3,2,1]
5
ghci> minimum [5,4,3,2,1]
1
ghci> sum [5,4,3,2,1]
15
ghci> product [5,4,3,2,1]
120
ghci> 4 `elem` [5,4,3,2,1]
True
ghci> 10 `elem` [5,4,3,2,1]
False

1.4 レンジでチン

手入力はだるい→レンジを使おう

ghci> [1..20]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
ghci> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"
ghci> [2,4..20]
[2,4,6,8,10,12,14,16,18,20]
ghci> [3,4..20]
[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
ghci> [3,6..20]
[3,6,9,12,15,18]

(でもレンジはそこまで賢くはない)

ghci> take 10 (cycle [1,2,3])
[1,2,3,1,2,3,1,2,3,1]

1.5 リスト内包表記

ghci> [x*2 | x <- [1..10]]
[2,4,6,8,10,12,14,16,18,20]
ghci> [x*2 | x <- [1..10], x*2 >= 12]
[12,14,16,18,20]
ghci> [ x*y | x <- [2,5,10], y <- [8,10,11]]
[16,20,22,40,50,55,80,100,110]

1.6 タプル

リストとタプルは違う

  1. 複数の違う型の要素を格納できる
  2. サイズが固定

2次元ベクトルみたいな使い方がなされる

ghci> (1, 3)
(1,3)
ghci> (3, 'a', "hello")
(3,'a',"hello")

タプルは固定長なので、タプルに要素を追加する関数は用意されていない

サイズ2のタプル ペア用の関数があったりする

ghci> fst (8, 11)
8
ghci> fst ("Wow", False)
"Wow"
ghci> snd (8, 11)
11
ghci> snd ("Wow", False)
False

なお、Haskellは遅延評価なので、有限リストと無限リストをzipすることもできる

直角三角形をみつける

タプルとリスト内包表記を組み合わせることもできる

rightTriangles' = [ (a,b,c) | c <- [1..10], a <- [1..c], b <- [1..a], a^2 + b^2 == c^2, a+b+c == 24]

main = do
  print $ rightTriangles'

[(8,6,10)]

感想

サンプルコードの実行とメモが追いついていないので、サンプルコードの実行はぼちぼちにして文章を読んだほうが良いかもしれないと感じました。