 Nabe
 Twitter: @nabe256
Haskell
   Haskell は高階関数や静的多相型付け、定義可
    能な演算子、例外処理といった多くの言語で採
    用されている現代的な機能に加え、パターン
    マッチングやカリー化、リスト内包表記、ガー
    ドといった多くの特徴的な機能を持っている。
    また、遅延評価や再帰的な関数や代数的データ
    型もサポートしているほか、独自の概念として
    圏論のアイデアを利用し参照透過性を壊すこと
    なく副作用のある操作(例えば 代入、入出力、
    配列など)を実現するモナドを含む。
                       (by Wikipedia)
   一言で言うと


    関数型言語
    です。
   ちょっとだけ詳しく言うと


    純粋関数型
    プログラミング言語
    です。
   手続き型言語
    › 記述された命令を逐次実行していく。
    › 一般的に用いられる言語。
   関数型言語
    › すべての計算は関数の評価で行われる。
    › 変数が無く、定数しか無い。
    › 手続き型でのループは再帰で実現する他、
    様々な機能が別の形で実現されている。
   その他の種類について興味のある方は
    「プログラミングパラダイム」という
    キーワードで調べると良いでしょう。
 基本的に副作用が無いため、
  原因不明のバグが出ることが少ない。
 どういう物が必要かを記述していけば
  書けてしまうので、短時間での開発が可能。
   クイックソートの例
qsort []     = []
qsort (x:xs) = qsort smaller ++ [x] ++ qsort larger
               where
                  smaller = [a | a <- xs, a <= x]
                  larger = [b | b <- xs, b > x]


   非常に簡潔に記述出来る。
   代表的なもの
    › 再帰関数(自分自身を呼び出す関数)
    › λ式(ラムダ式、無名関数)
    › 無限リスト(長さが無限のデータ)
    › 遅延評価 (必要な時まで式を評価しない)
    › 高階関数(関数の引数または返り値が関数)
    › 純粋 (基本的に副作用が無い)
    › モナド(副作用を扱う仕組み)
   他多数!
   Haskellが使用されているプロジェクト
    › Pugs
        HaskellによるPerl6の実装
    ›   darcs
        分散バージョン管理システム
    ›   Whitespace
        タブ・空白・改行のみで記述する言語
    ›   Monadius
        グラディウス風のゲーム
    ›   Mighttpd (発音:Mighty)
        HTTPサーバ
   基本的な文法をいくつか覚える。
    簡単なプログラムを書けるように
    なれれば素敵。
 GHC (Glasgow Haskell Compiler)
  Haskellにおける事実上の標準コンパイラ。
  実行が高速で、ライブラリ多数。
 Hugs
  軽量なコンパイラ、基礎を学ぶには十分。
  導入も簡単だが開発は停止している模様。
 Haskell Platform
  Haskell処理系のGHCに加えて
  各種ツールやライブラリが揃っている。
 UNIXであれば
  GHCか、可能であればHaskell Platformを。
 Windowsであれば
  Haskell Platformが最適。

   高度な事をするのであれば、
    UNIXならGCC
    WindowsならMinGW
    などが必要。
   今回はGHCに付属する
    › コンパイラのGHC
    › インタプリタのGHCI
  を使用します。
 環境がある方は挑戦してみましょう。
   まずはインタプリタから
    実行してみます。
   Win/UNIXならghci、MinGWならghcii.shを起動します。
   $ ghci
    GHCi, version 7.0.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.
    Loading package ffi-1.0 ... linking ... done.
    Prelude>
   Prelude(標準ライブラリ)が出てくれば準備完了です。
   :quit または :q で終了します。
    Prelude> :q
    Leaving GHCi.
    $
 いくつか試してみましょう
> 256
256
> 1+2*3
7
> 7/2
3.5
> 2^256
 結合順位もしっかりあります
> 8/4/2
1.0
> 2^3^2
512
> (2^3)^2
64
 :typeで型が見られます。(:t と略せる)
> :type 256
256 :: Num a => a
> :t 1+2
1+2 :: Num a => a
> :t 3.5
3.5 :: Fractional a => a
> :t 7/2
   関数は :info で見ると色々情報が出ます。
    (:i と略せる)
> :info (+)
class (Eq a, Show a) => Num a where
  (+) :: a -> a -> a
  ...
        -- Defined in GHC.Num
infixl 6 +
 Haskellでは型が非常に重要な要素です。
 型が分かればHaskellを理解する
  良い手がかりになります。
 型の詳細は後ほど。
 文字関係です。
> „a‟
„a‟
> “Hello”
Hello
 リストを使ってみます。
> [1,2,3]
[1,2,3]
> head [1,2,3]
1
> tail [1,2,3]
[2,3]
 リストは色々な操作が可能です。
> [1,2,3,4,5] !! 2
3
> take 3 [1,2,3,4,5]
[1,2,3]
> drop 3 [1,2,3,4,5]
[4,5]
> reverse [1,2,3,4,5]
[5,4,3,2,1]
  長さも変更可能です。
> length [1,2,3,4,5]
5
> length (tail [1,2,3,4,5])
4
> [1,2,3] ++ [4,5]
[1,2,3,4,5]
 : 演算子(cons)
> 1:2
[1,2]
> 1:[2,3]
[1,2,3]
 同じ型式でないといけません。
  以下はエラーが発生します。
> [1,„a‟]
> [1,“Hello”]
 ちなみに、文字と文字列の関係
> [„a‟,„b‟,„c‟]
“abc”

   文字列は文字のリスト、ということです。
 タプルを使ってみます。
> (1,2)
(1,2)
> (1,2,3)
(1,2,3)
 長さを変えられない代わりに、
  違う型でも使えます。
> (1,‟a‟)
(1,‟a‟)
> (1,”Hello”)
(1,”Hello”)
> (1,'a',"hello",[1,2,3])
(1,'a',"hello",[1,2,3])
 タプルを使った関数。
> fst (1,”hello”)
1
> snd (1,”hello”)
”hello”
Prelude> putStrLn “Hello, World!”
Hello, World!

   Hello, World! と出力してくれる
    おなじみのサンプルです。
putStrLn “Hello, World!”

   関数を適用する場合は
    空白文字を使います。
Prelude> take 3 [1,2,3,4,5]
[1,2,3]

 2引数の関数です。
  リストから指定した数の要素を
  取り出します。
 2つ以上の引数に対して関数適用する場合も
  空白文字を使います。
Prelude> take 3 (tail [1,2,3,4,5])
[2,3,4]

   引数に関数を渡す場合は括弧を使います。
   関数を定義して実行してみましょう。
$ ghci
Prelude> let main = putStrLn “Hello, World!”

 等式の左辺が関数名、
  右辺は関数の内容になります。
 let 関数名=関数の内容
  という形式です。
 先ほど定義したmainを使用してみます。
Prelude> main
Hello, World!
 実行出来ました。
 先ほどはインタプリタで実行しました。
 ならば今度は
  コンパイルして実行してみましょう。
   以下の行をhello.hsというファイルに
    保存します。

main = putStrLn “Hello, World!”

 関数名=関数の内容という形式です。
  先程と同様に等式の左辺が関数名、
  右辺は関数の内容になります。
 こちらが一般的な書き方です。
  先ほどのletはインタプリタ用と考えてください。
   hello.hsをコマンドラインから
    コンパイルして実行してみます。

$ ghc --make hello.hs
$ ./hello
Hello, World!
$

   実行できました。
 実際にHaskellを扱うに当たって
  コードを記述して実行する方法は
  いくつかあります。
 先程の例
    › インタプリタ上で記述して実行
    › ソースをコンパイルして実行
 実際にHaskellを扱うに当たって
  コードを記述して実行する方法は
  いくつかあります。
 その他
    › ソースをインタプリタに渡して実行
    › ソースをインタプリタから読み込んで実行
 ソースをインタプリタに渡して実行
$ ghci hello.hs
Ok, modules loaded: Main.
Prelude Main> main
Hello, World!
Prelude Main> :q
$
 ソースをインタプリタから読み込んで実行
$ ghci
Prelude> :load hello.hs
Ok, modules loaded: Main.
Prelude Main> main
Hello, World!
Prelude Main> :q
$
   コンパイルして実行する場合
    › 高速に実行できる
    › 実行するにはmainを定義する必要がある
   インタプリタで実行する場合
    › 便利な機能が沢山あるので
      学習する時に非常に便利
    › mainを定義しなくても良い
   :reloadで再読み込みが出来る
   先程のhello.hsを読み込む。

> :load hello.hs
> main
Hello, World!
 GHCIを起動したまま、
  別ウィンドウでhello.hsを編集する。
$ cat hello.hs
main = putStrLn “Hello, World!”
$ #編集
$ cat hello.hs
main = putStrLn “Hello, Haskell!”
 GHCIのウィンドウに戻り、
  再読み込み。
> :load hello.hs
> main
Hello, World!
> :reload
 GHCIのウィンドウに戻り、
  再読み込み。そして実行。
> :load hello.hs
> main
Hello, World!
> :reload
> main
Hello, Haskell!
   インタプリタならではのやり方でした。
   あとは :type や :info など。
    調べるのに便利な機能が色々あります。
 Haskellは型が重要。
 型さえ覚えれば
  第一の突破口クリア。
 1引数の関数を見てみる
  headを見てみる
> head [1,2,3]
1
> :t head
head :: [a] -> a
head :: [a] -> a
head :: [a] -> a
関数名
head :: [a] -> a
    これ以降は型を表す
head :: [a] -> a
        型
head :: [a] -> a
               a型
               任意の型
head :: [a] -> a
        [a]型
        任意のリスト型
head :: [a] -> a
        [a] -> a型
        [a]型からa型へと変換する型
head :: [a] -> a
        [a] -> a型
        [a]型からa型へと変換する関数
head :: [a] -> a
        [a] -> a型
        任意のリスト型から任意の型へと
        変換する関数
a型を具体的な型に置き換えるため、
先程の例

> head [1,2,3]
1

を当てはめてみる。
head :: [a] -> a
        [a] -> a型
        任意のリスト型から任意の型へと
        変換する関数
head :: [Num] -> Num
        [Num] -> Num型
        数値のリスト型から数値型へと
        変換する関数
head :: [Num] -> Num
headは[Num] -> Num型
数値のリスト型から数値型へと
変換する関数
head :: [Num] -> Num
headは[Num] -> Num型
数値のリスト型から数値型へと
変換する関数

本当にそうなのか確認。
> head [1,2,3]

1
> head [1,2,3]
       数値のリスト型
1
数値型
> head [1,2,3]
       数値のリスト型
1
数値型

数値のリスト型から
数値型へと正しく変換されている。
 1引数の関数を見てみる(2)
  sumを見てみる
> sum [1,2,3,4,5]
15
> :t sum
sum :: Num a => [a] -> a
 型の読み方
sum :: Num a => [a] -> a
 型の読み方
sum :: Num a => [a] -> a
関数名
 型の読み方
sum :: Num a => [a] -> a
       sum関数の型
 型の読み方
sum :: Num a => [a] -> a
                 [a]型をa型に変換する関数
 型の読み方
sum :: Num a => [a] -> a
       aを数値型とするクラス
 型の読み方
sum :: Num a => [a] -> a
                数値のリスト型を
                数値型に変換する関数
 型の読み方
sum :: Num a => [a] -> a
                数値のリスト型を
                数値型に変換する関数
本当にそうなのか確認
> sum [1,2,3,4,5]

15
> sum [1,2,3,4,5]
      数値のリスト型
15
数値型

数値のリスト型から数値型へ
正しく変換されている
 2引数の関数を見てみる(1)
  takeを見てみる
> take 3 [1,2,3,4,5]
[1,2,3]
> :t take
take :: Int -> [a] -> [a]
take :: Int -> [a] -> [a]
take :: Int -> [a] -> [a]
関数名
take :: Int -> [a] -> [a]
        型
take :: Int -> ([a] -> [a])
        右結合なので
        このように解釈する
take :: Int -> ([a] -> [a])
                [a]型を受け取り
                [a]型を返す関数
take :: Int -> ([a] -> [a])
                関数A
take :: Int -> ([a] -> [a])
        Int型を受け取り
        関数Aを返す関数
take :: Int -> ([a] -> [a])
        Int型を受け取り
               関数A
        を返す関数
take :: Int -> ([a] -> [a])
        Int型を受け取り
               ([a]型を受け取り
                [a]型を返す関数)
        を返す関数
take :: Int -> [a] -> [a]
        Int型を受け取り
        [a]型を受け取り
        [a]型を返す関数
        を返す関数
take :: Int -> [a] -> [a]
        Int型を受け取り
        [a]型を受け取り
        [a]型を返す関数
        を返す関数
言い換えると
take :: Int -> [a] -> [a]
        Int型と[a]型を受け取り
        [a]型を返す関数
という事です
   非常に分かりづらいので
    順を追って解読してみる。
 takeにInt型の値(2)を渡してみる
take :: Int -> [a] -> [a]
        Int型を受け取り
        [a]型を受け取り
        [a]型を返す関数
        を返す関数
 takeにInt型の値(2)を渡してみる
(take 2) :: Int -> [a] -> [a]
       Int型を受け取り
       [a]型を受け取り
       [a]型を返す関数
       を返す関数
 takeにInt型の値(2)を渡してみる
(take 2) :: Int -> [a] -> [a]
       Int型を受け取り
       [a]型を受け取り
       [a]型を返す関数
       を返す関数
 takeにInt型の値(2)を渡してみる
(take 2) :: [a] -> [a]
       [a]型を受け取り
       [a]型を返す関数
 (take 2)に[a]型の値([4,5,6])を渡してみる
(take 2) :: [a] -> [a]
       [a]型を受け取り
       [a]型を返す関数
 (take 2)に[a]型の値([4,5,6])を渡してみる
(take 2 [4,5,6]) :: [a] -> [a]
       [a]型を受け取り
       [a]型を返す関数
 (take 2)に[a]型の値([4,5,6])を渡してみる
(take 2 [4,5,6]) :: [a] -> [a]
       [a]型を受け取り
       [a]型を返す関数
 (take 2)に[a]型の値([4,5,6])を渡してみる
(take 2 [4,5,6]) :: [a]
       [a]型を返す関数
 (take 2)に[a]型の値([4,5,6])を渡してみる
(take 2 [4,5,6]) = [4,5]
       [a]型を返す関数
 (take 2)に[a]型の値([4,5,6])を渡してみる
(take 2 [4,5,6]) = [4,5]
       [4,5]を返す関数
 (take 2)に[a]型の値([4,5,6])を渡してみる
(take 2 [4,5,6]) = [4,5]
結果 = [4,5]
本当にそうなのか確認
> take 2 [4,5,6]

[4,5]
> take 2    [4,5,6]
       Int型
[4,5]
> take 2    [4,5,6]
       Int型 [a]型
[4,5]
> take 2    [4,5,6]
       Int型 [a]型
[4,5]
[a]型
> take 2    [4,5,6]
       Int型 [a]型
[4,5]
[a]型

どうやら本当になったようです。
   実際にGHCIでも確認してみましょう。
> :t take
take :: Int -> [a] -> [a]

> :t take 2
take 2 :: [a] -> [a]

> :t take 2 [4,5,6]
take 2 [4,5,6] :: Num a => [a]

> take 2 [4,5,6]
[4,5]
   確かにそのように動作していました。
 少々かみ砕きすぎたでしょうか。
  余計難しくなったかも知れません。
 一言で説明しても順を追って説明しても
  難解な概念ですが、何度かソースを書いて
  試して見ると、急にすっと分かるように
  なります。
 型を意識して作る必要があります。
 型を考えるという事は
  入力の形と出力の形を考える事、
  そして関数の入出力と処理内容を
  切り分ける事へと繋がります。
 型の概念は難しい部分がありますが、
  型が分かるようになると
  難しい事を考えなくても
  プログラムが書けるようになります。
 全体的に駆け足で説明する事に
  なってしまいました。
 Haskellが分かるようになると
  いつの間にか面白いと思うようになります。
 ありがとうございました。

Haskell超入門 Part.1