SE情報技術研究会’s blog

http://se-info-tech.connpass.com

2015-12-13 『ふつうのHaskellプログラミング』 もくもく読書会(第2章) の振り返り

ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門

ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門

第2章 Haskellの基礎(1) 関数とリスト

Hello, World!! の文法

  • 識別子は大文字と小文字が区別される
main = putStrLn "Hello, World!"
  • mainは変数
  • putStrLn "Hello, World!は値
  • 値は関数ではなくaction(actionについては第11章で説明)

Haskellではプログラムを開始するとmainアクションの評価から処理が開始される

  • "Hello, World"putStrLn関数の引数
  • 引数を例のように括弧でくくらないで空白の後に置く → 括弧でくくることも可能

Haskellでは引数を渡して関数を呼び出すことを「引数に関数を適用(apply)する」という

疑問点

関数とアクションの定義の違いがいまいちわからない
→ 11章で説明されるのか?

cat.hs

  • 入力された内容をそのまま標準出力する
  • 事前にソースファイルと同じフォルダにUSA-states.txtが必要

ソースの内容

  1. getContentsアクションは「標準入力を読み込むという契約」
  2. 変数csに束縛されているのはgetContentsアクション
  3. putStr関数で変数csを参照した時に初めてgetContentsアクションが活性化されテキストを読み込み文字列を返す

WindowsならCtrl+Z+Enterで終了とあるが同時押しではなくCtrl+Zは同時に押した後にEnter。 Ctrl+Cでいきなり終了させることも可能。

getContents

  • 標準入力を全て読み込むアクション

putStr関数

  • 改行なしの引数の文字列を出力する関数
  • ここではファイル内に改行があるので関数での改行は不要

do式

do 構文1
   構文2
   構文3
   ・・・
  • 複数の式を束ねる構文
  • 構文ごとのインデントをそろえないといけない
  • do式でまとめるとアクションが上から下に実行される(構文1 → 構文2 → 構文3・・・)
  • do式でまとめないと上から下に実行されるか保証されない → 遅延評価のため

<-

  • アクションの結果を得るときに使う構文:変数名 <- アクション
  • 変数と値を結び付けることを「変数を値に束縛(bind)する」と言う
  • 右辺にはアクションなどの限られた型の値にしか使えない
  • do式など限られた所でしか使えない

countline.hs

標準入力の行数を数える

リスト

  • 同じ型の値を一列に並べたデータ構造(一方行リンクリストと同じ)
  • 末尾は空リスト
  • Haskellでは文字列は文字のリスト(文字列は存在しない)

書式

[ 値1,値2 ,値3・・・ ]

「$」演算子

  • 二項演算子
  • 演算をする目的よりも式を区切るために使われる
print $ length $ line cs

print $length (line cs)

print (length (line cs))

lines関数

  • 文字列を行ごとのリストにする関数
  • 改行文字は取り除かれる
"aaa
bbb
ccc"

↓ リストになる

["aaa", "bbb", "ccc"]

疑問点

  • lines関数の改行文字はCR+LFでもLFでも区別できるのか?
    → できるもよう。 下記を作成し改行LFのテキストと改行CR+LFのテキストを読み込ませたが結果は正しくリストになっていた
main = do cs <- getContents
          print $ lines cs

Windows環境で実施

head.hs

  • 標準出力の最初の10行のみ取得する

firstNLines関数を定義する

  • 対象文字列を第1引数の行数分だけ取得する関数
  • 引数が2つある

引数が2つある場合は空白で区切って指定することが可能

firstNLines 行数 対象文字列

unlines関数

  • 文字列のリストを連結して行つきの文字列にする関数
  • lines関数の逆

take関数

  • リストの先頭からn要素をとってリストで返す関数
  • リストが指定されたnより少ない場合はリスト全体を返す
> take 3 [1, 2, 3, 4, 5]
[1, 2, 3]

tail.hs

  • 入力の最後の10行を表示する
  • headとは逆

reverse関数

  • リストを逆順にする
> reverse [1, 2, 3]
[3, 2, 1]

練習問題

答え1

本の解答は下記

main = do cs <- getContents
          print $ length cs
  • 問題文にはバイト数とあるが日本語入力は対象外のもよう。(日本語はエラーになる)
  • countlineとして入力するのではなくcountline < ファイル名でテキストファイルを読み込んでそのバイト数を返す
    → テキストを指定していないと入力後にEnterかCtrl+Cなどが含まれるのか変な値が出力される
  • テキストファイルに改行を含んでいるともちろん1文字と数える

答え2

本の解答は下記

main = do cs <- getContents
          print $ length $ words cs

これは特に問題なし。改行で区切ったのも問題なかった。

(その他雑談など)

  • Haskellは標準のコーディング規約がないらしい
  • 最初にHaskellを勉強するにはよい本かも?
    → 既にHaskellをかじっているから、頭に入りやすいのか?
  • 章を進めていくと本が古い分、importするモジュールが変わっていてそのままだと動かないらしい
    → ここら辺は初めての人は知らないとドツボに嵌まるかも?
  • 朝はきついので次週から月曜の夜に変更