10000hの技術メモ

この先生きのこるための勉強内容&時間記録

Haskell入門 7.1

Haskell入門 関数型プログラミング言語の基礎と実践

Haskell入門 関数型プログラミング言語の基礎と実践

2章や3章をやってみて、正直ひとつひとつの要素を「ふーん」と読んでいってもいまいちわからなかったので、ここはひとつ、先まで飛ばしていってとりあえずコードを書き始めてからもどって来ようと思いました。

7.1 標準ライブラリ

Preludeモジュールは暗黙的にインポートされるので、Preludeモジュールの関数=組み込み関数とも言える。

Data.Bitsはビット演算のための関数を提供。

モジュールのimportはimport Data.Bitsのように行う。やらないと(当たり前だけど)中の関数は使えない。試しに、インポート前後の比較をしてみた。

*Main Lib> b = 0x05 :: Word -- 0x05 : 0000 0101
*Main Lib> testBit b 0

<interactive>:2:1: error:
    Variable not in scope: testBit :: Word -> Integer -> t
*Main Lib> import Data.Bits
*Main Lib Data.Bits> testBit b 0
True

Data.Charは文字に関する関数を提供するモジュール

Data.List[a]型に関する関数が定義されたモジュール。Listに関するほとんどの関数はPreludeモジュールに入っている。Data.Listのほうに入っているのは、例えば

  • group
  • oartition
  • nub
  • interspere

など。

これ、ProjectEulerやってるころにHaskell使ってたらもっとスムーズだった気がしてきた。。

groupを使った例

*Main Lib Data.Bits Data.Char> import Data.List
*Main Lib Data.Bits Data.Char Data.List> group [3, 3, 5, 3, 3, 3, 1, 1]
[[3,3],[5],[3,3,3],[1,1]]

3をまとめるわけではないみたい。

intercalateを使った例

*Main Lib Data.Bits Data.Char Data.List> intercalate [] [[1,2,3],[2,3],[4,5]]
[1,2,3,2,3,4,5]
*Main Lib Data.Bits Data.Char Data.List> intercalate ", " ["abc", "de", "fghi"]
"abc, de, fghi"

第一引数で区切って第二引数の中身を結合するようで、上に出したような、リストのリストからリストにするとか、文字列のリストから文字列にするときに便利みたい。

inPrefixOfなどを使ったときの例で、

*Main Lib Data.Bits Data.Char Data.List> "hoge" `isPrefixOf` "hogehoge"
True

と本にはあった。 Haskellでは"`"をつけると関数を中置にできるようで。自分は使わない気がするけど面白い。

Data.Array

イミュータブルな配列を提供します。Data.Arrayによる配列はリストとは違い、添字によって各要素へ高速にアクセスできます。

今回の勉強時間:1時間 累計勉強時間:21時間58分

Haskell入門 2.4 〜 3.2

Haskell入門 関数型プログラミング言語の基礎と実践

Haskell入門 関数型プログラミング言語の基礎と実践

2.4 関数

関数呼び出しは

関数 引数

の形で呼んでいた。

関数定義は

関数 引数 = 式

の形で行う。

> incr n = n + 1 :: Int

ラムダ式を書く場合

> (¥n -> n + 1 :: Int)

カリー化

カリー化(currying)とは、多引数の関数を関数を返す関数として表現することです。

はい。

. による関数合成

f . g = ¥x -> f (g x)

ここで

f . g と合成すると、引数に対してまずgを適用して、次にその返り値にfを適用する関数になります

とあるけれど、関数適用って値を関数に適用するんじゃなかったっけ?(うろおぼえ)

ラムダ計算 - Wikipedia

遅延評価と非正格性

多くのプログラミング言語:関数を呼び出す前に引数の式を計算する=先行評価 Haskell:遅延評価

引数に⊥を渡したときに結果が⊥になるような関数を正格な関数(strict function)と言う。 ⊥を渡しても結果が⊥とはならない関数を非正格な関数(non-strict function)と言う。

書き方によって評価順序の制御をがんばることも可能。

main関数とdo式

はい。

・・・2章、読んでいるだけだとあまりスっと入ってこないので、一度飛ばして先に進んで、サンプルコードを読み書きしていて詰まったら戻ってくることにする。

3章へ進む。

3.2 型システム

式に型を割り当てて、正しく組み立てられているか確かめる仕組みのこと

型チェック

型付け規則に従っているかどうかをチェックする。このおかげで、静的型付き言語では炊かに起因する問題がおきない

多様性

任意の型の値に対して適用できる関数sample

*Main Lib> sample x = x
*Main Lib> :t x
x :: Num t => t
*Main Lib> sample2Params f x = f x
*Main Lib> :t sample2Params
sample2Params :: (t1 -> t) -> t1 -> t

tは汎用の型を表す型変数で、複数の具体的な型で利用できるようにした型システムはパラメータ多相(parametric polymorphism)を持つという。

アドホック多相

オブジェクト思考で言うオーバーロード。渡す値の型によって違う動きをする。

型推論(type inference)

処理系が自動で型を付けてくれる。

Haskellの型システムはHindley-Milnerの型システムを基にしている。

Hindley–Milner type system - Wikipedia

今回の勉強時間 1時間 累計勉強時間 20時間58分

Haskell入門 1.4 〜 2.3

Haskell入門 関数型プログラミング言語の基礎と実践

Haskell入門 関数型プログラミング言語の基礎と実践

1.4 プロジェクト作成とビルド

stackでプロジェクトを作成してビルドする。

$ stack new [project name]
  • stack.yaml・・・ビルド情報を記載するファイル
  • projectname.cabal、Seup.hs、LICENSE・・・Cabal形式のパッケージの管理

cabalって何?

本書の該当章には書いてなかったものの、Cabalとは。

RubyでいうGemのようなパッケージシステムとのこと。

参照:Haskellのパッケージシステム (Cabal) | Netsphere Laboratories

ビルド

$ stack build

これで実行ファイルprojectname-exeが作られるはずだが、ディレクトリ内を探しても見つからず。ところが

$ stack exec projectname-exe

を実行すると、期待通りの動作をした。

サンプルコードには含まれていないが、単体テストをする場合は

$ stack test

第2章 基本の文法

2.1 文法の特色

手続き型言語ではコンピュータへの指示を文として上から順に並べて書くのに対し、関数型言語では細かな式をたくさん定義してそれらを組み合わせてプログラムを構築します。

2.2 基本のデータ型

> 値 :: 型

文字と文字列は明確に区別。 シングルクオートは文字でChar型、ダブルクオートは文字列でString型。

> :t 値

で値の型を表示する。

show関数を使うと、色々な値を文字列にできる。

I/Oアクション

I/Oアクションは IO a型で表す。(aは型変数)。 例えばputStrLnの返り値はIO ()型で、Unit型の()を返しつつ画面にprintする。

ボトム

式の評価が正しく終わらないことを、ボトムといいます。

たとえば

  • undefined
  • error

といった式。

2.3 変数

Haskellでは=によって示した変数に対応するデータを後から変更できません。変更のできない変数のことを、一般的にイミュータブル(immutable)であると言います。

変数を宣言してその内容を決めるkとおを、Haskellでは変数(binding)と言います。

  • whlere
  • let ~ in ~ 式 ← OCamlでとても使ったやつ

今回の勉強時間 45分

累計勉強時間 19時間58分

Haskell入門 1.2 〜 1.3

Haskell入門 関数型プログラミング言語の基礎と実践

Haskell入門 関数型プログラミング言語の基礎と実践

コンパイラとしてGHC、ビルドツールとしてStackを使う。

1.2 実行環境の構築

Stackのインストール

curl -sSL https://get.haskellstack.org/ | sh

WARNINGが出た。

WARNING: '/Users/yoshikiito/.local/bin' is not on your PATH.
    For best results, please add it to the beginning of PATH in your profile.

一旦スルー。

GHCのインストールなど

$ stack setup

ここでトラブる。

configure: WARNING: configure can't recognize your CPP program, you may need to set --with-hs-cpp-flags=FLAGS explicitly configure: error: in /Users/yoshikiito/.stack/programs/x86_64-osx/ghc-8.0.2.temp/ghc-8.0.2': configure: error: C compiler cannot create executables Seeconfig.log' for more details

Error: Error encountered while configuring GHC with /Users/yoshikiito/.stack/programs/x86_64-osx/ghc-8.0.2.temp/ghc-8.0.2/configure --prefix=/Users/yoshikiito/.stack/programs/x86_64-osx/ghc-8.0.2/ run in /Users/yoshikiito/.stack/programs/x86_64-osx/ghc-8.0.2.temp/ghc-8.0.2/

ここで指定されたconfig.logの中身を見てみると、

$ sudo xcodebuild -license

しろと書いてあるので実行。

ライセンス条項に同意したのち、再度$stack setupを行うことで、インストールが完了した。

いちおう参考:c++ - Haskell Stack Setup - Can't Recognize CPP Program - Stack Overflow

1.3 REPLとスクリプトの実行

対話的な実行環境REPL(Read-Eval-Print Loop)

ghciはStackから起動する。

$stack ghci

各種commandは本を参照。

ファイルに書いたスクリプトを直接実行

$ stack runghc hello.hs

今回の勉強時間 1時間30分

累計勉強時間 19時間13分

Haskell入門 1.1 Haskellの特徴

Haskell入門 関数型プログラミング言語の基礎と実践

Haskell入門 関数型プログラミング言語の基礎と実践

1.1 Haskellの特徴

CやJavaとはプログラミングパラダイムが異なる。 Haskellの特徴は - 関数型 - 静的型付け - 純粋性 - 型推論 - 遅延評価

関数型プログラミングの定義

引数に対して値が決まる、数学的な関数を中心に計算を表現するプログラミングスタイル

参照透過性

関数を同じ値となる式に対して呼んだときに必ず同じ結果となる性質

C言語など手続き型言語でいう「関数」と、関数型プログラミングの「関数」の違いはここで、後者の関数とは数学的な関数のことをさす。

静的型付け(static typing)

プログラム内の変数や関数の引数・返り値について、型をプログラムの実行前にすべて決めること

→型に関するバグを実行前に見つけることができる。

純粋関数型プログラミング言語

すべての関数が参照透過性を持つような関数型プログラミング言語

すべての変数はイミュータブル(変更不能)

IO型、IOモナド

今回の勉強時間 11分

累積勉強時間 17時間43分