[[プログラミング]] *Haskell [#qe34fb41] #contents ---- **Programming in Haskell [#jfaa53b7] -Graham Hutton著の「Programming in Haskell」や参考リンクのスライドに関するメモ。 --ちなみにオーム社から翻訳版として「Haskellプログラミング」というタイトルで出版されている。 ***第1章 導入 (Introduction) [#g4112448] - ***第2章 はじめの一歩 (First Steps) [#hc13dafd] - ***第3章 型とクラス (Types and classes) [#e28d8b9a] ***第4章 関数定義 (Defining functions) [#y4b4b199] ***第5章 リスト内包表記 (List comprehensions) [#rf740073] ***第6章 再帰関数 (Recursive functions) [#w0d93fa7] ***第7章 高階関数 (Higher-order functions) [#o0ebd248] ***第8章 関数型パーサー (Functional parsers) [#y6012088] ***第9章 対話プログラム (Interactive programs) [#pf099b05] ***第10章 型とクラスの定義 (Declaring types and classes) [#o7aa1d34] ***第11章 切符番号遊び (The countdown problem) [#o956c676] ***第12章 遅延評価 (Lazy evaluation) [#gd52ef8a] ***第13章 プログラムの論証 (Reasoning about programs) [#bb50e0f7] **ふつうのHaskellプログラミング [#s1d34753] -青木峰郎著の「ふつうのHaskellプログラミング」に関するメモ。 ***第1章 [#ia9acaad] -高階関数 --引数や戻り値として関数を取る関数。 -多相型(polymorphic type) --Javaでいう総称型(generic type)、C++とかではtemplate -遅延評価 --式を評価する方式の一つ。最初に数値(引数)の評価では無く、関数の評価を行う。Haskellは遅延評価を基本としている。 ***第2章 [#c05a3326] -mainアクション --Haskellでは実行するとmainアクションの評価が始まる。 -関数の適用 --以下におなじみの"Hello, World!"のHaskellでの例を示す。Haskellでは、"Hello, World!"に関数putStrLnを適用する(apply)と言い、そのアクションを評価することにより、Hello, Worldが表示される。 main = putStrLn "Hello, World!" --ちなみに""中にエスケープシーケンスも代入可能。 -レイアウト --do式等に記述される後続の複数のアクションは同一のインデントでなければならない。 --Javaでいうブロック構文 --別名、オフサイドルール(off-side rule)と言う。 -$演算子 --関数の戻り値を新たに関数の引数として利用するなど、複数の関数を連続して書きたい場合、従来の言語では括弧のネストが見づらかったが、$演算子を用いることにより、スマートに記述が可能。 f (g ( h "Hello, World!")) f $ g $ h "Hello, World!" -lines及びunlines関数 --lines :: String -> [String]~ 改行区切りの文字列をStringのリストにする。 --unlines :: [String] -> String~ Stringのリストを改行区切りの文字列にする。 ***第3章 [#n0816b65] -型推論 --言語処理系がその型を前後の文脈などによって自動的に推論する仕組み -型変数 --例としてlength関数の型は以下のとおりである。 [a] -> Int --aに限らず、アルファベットの小文字から始まる変数を、型変数という。ちなみに多相型は型変数を含む型のことである。 --関数が以下のような型の場合、同じである可能性もあるが、aとbは同じでなくても良い。 [a] -> [b] -if式 --Haskellでは三項演算子のように、if全体が値を持つ。なのでif式。 if 条件式 then 式1 else 式2 --とか if 条件式 then 式1 else 式2 --等。 ***第4章 [#p94200e1] -コマンドライン引数取得 --Haskellでコマンドライン引数を取得するには、SystemモジュールのgetArgsアクションを用いる。 --以下はechoコマンドの一例 import System main = do args <- getArgs putStrLn $ unwords args --unwords :: [String]->String~ ["a","b","c"]を"a b c"のように、空白区切りにする関数。 -Mainモジュール --どの変数も、何らかのモジュールに所属している。Haskellではファイルに明示的にモジュールを宣言しない場合、main変数だけが公開されている、Mainモジュールとなる。 -Preludeモジュール --getContentsや、リストの操作関数は全てPreludeモジュール内で定義されている。原則、暗黙にインポートされる。 -where節 --式で一時的に使用する変数(関数)の定義に用いる。whereの中で定義した変数はwhere節を記述した関数以外からは参照不可。whereの中からは外側の変数を参照可能。 式 where 定義1 定義2 --や 式 where 定義1 定義2 --等。 -filter関数 --filter :: (a -> Bool) -> [a] -> [a]~ 型がa -> Boolである関数を、リスト[a]の各要素に適用し、Trueである要素のみを取り出す関数。 -any関数 --any :: (a -> Bool) -> [a] -> Bool~ 型がa -> Boolである関数を、リスト[a]の各要素に適用し、いずれかの値がTrueならば、Trueを返す関数。 ***第5章 [#k2ee8998] -置き換えモデル(substitution model) --Haskellにおいて、式の評価は置き換えモデルによって表現される。 --置き換えモデルでは関数の適用は定義で置き換えていくことにより、評価を行う。 --例えば f n = n*n --という定義の関数がある場合、f (1+2)を評価する際に、まずは以下のように置き換えが行われる。 f (1+2) => (1+2)*(1+2) => 3*3 --Haskellでは、加算や乗算の演算子も関数であるので、上記式はさらに置き換えが行われ、結果として評価した値を得る。 --この置き換えのプロセスを、簡約と言う。 -最内簡約(innermost reduction)及び最外簡約(outermost reduction) --置き換えモデルで説明した通り、Haskellでは引数より先に関数の展開が行われる。これを最外簡約と言う。 --一方、C言語等では以下のように簡約される。これを最内簡約と言う。 f (1+2) => f 3 => 3*3 -グラフ簡約(graph reduction) --最内簡約の手順では、引数が簡約によって複数箇所に登場する(例えば1+2)。これらの引数に与えられた式の評価は、個別に行われるのではなくあくまでも一度だけ行われ、その結果を共有している。 --このように評価された式を全体で共有しながら簡約する方法を、グラフ簡約と言う。 -遅延評価(lazy evaluation) --遅延評価とは、式や値などの評価を、実際に必要とするまで行わないことを言う。 --以下のプログラムでは、先頭の100+100のみ評価が行われ、後述の要素の評価は行われない。 head [100+100,123*321,200-2] --式や値が必要とされるという判断として、パターンマッチと組み込みの演算の2種類が挙げられる。 -参照透過性(referential transparency) --参照透過性とは、ある変数や関数等で構成される式があった場合、その式の評価結果は常に一定であるということ。言い換えると、変数もまた一定であり関数も同じ引数である限り一定である。 -副作用 --変数への再代入など、それ以降で評価される式の結果に対して影響を与えることを、副作用と言う。 --Haskellでは、主に画面への出力やキーボードからの入力がそれに相当する。 --入出力を用いた場合でも参照透過性を維持するために、HaskellではIOモナドという、特殊な仕組みを利用する。 ***第6章 [#jf340114] -整除 --Haskellでは整数の除法及び剰余に対して、4種類の演算子が定義されている。 --C言語において、剰余演算子は(a/b)*b+(a%b)=aが成立するような、aとbの組み合わせと定義されている。しかし、aかbのオペランドが負数であった場合、0方向でまるめるか負の無限大方向へまるめるかによって結果が異なる。 --C言語の標準規格であるC99においては、0方向でまるめることが定められている。 --Haskellではこれらに対応して、4種類の演算子が定義されている。 ---0方向として: 商 `quot` 剰余 `rem` ---負の無限対方向として: 商 `div` 剰余 `mod` -null関数 --null :: [a] -> Bool~ リストが空である場合にTrue、そうでない場合にFalse ***第7章 [#ydc58e3e] **環境設定 [#lfb9b429] ***Haskell mode (emacs) [#u31ea315] -Hasklellプログラミングをemacsでする為に、Haskell modeが存在する。 -以下のリンクから最新版のアーカイブをダウンロードし、適当な場所に解凍する(e.g. ~/share/emacs/site-lisp/haskell-mode-*.*.*/) --http://projects.haskell.org/haskellmode-emacs/ -~/.emacsに以下の記述を追加する。 ;; haskell (load "~/share/emacs/site-lisp/haskell-mode-*.*.*/haskell-site-file") (setq haskell-program-name "/usr/bin/ghci") --標準ではインタプリタとしてHugs 98が指定されているので、ghciを使用したいときにhaskell-program-nameを指定する。 -サブウィンドウでインタプリタを起動する M-x run-haskell -編集しているプログラムをインタプリタでロードする C-c C-l **参考リンク [#v1460dec] --http://www.cs.nott.ac.uk/~gmh/book.html