SE情報技術研究会’s blog

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

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

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

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

  • 作者: 青木峰郎,山下伸夫
  • 出版社/メーカー: SBクリエイティブ
  • 発売日: 2014/10/05
  • メディア: オンデマンド (ペーパーバック)
  • この商品を含むブログを見る

第6章 基本的な値

Bool型

  • True
  • False

関数

  • not
  • &&
  • ||

数値

  • 数値リテラルだけだと具体的な型が定まらない
    → 数値の型のどれにでも推測できるから
  • 数値リテラルの型を限定するには明示的に宣言する
  • 一度推論や定義された型から別の型への自動変換は行わない
::

例:

defaultWidth  (16 :: Int)
  • マイナス値はかっこ()をつけないとエラー
(-1)

整数型

  • Int
  • Integer
  • 10進表記、8進表記、16進表記の3つのリテラルで表現できる

Int

  • 比較的小さな範囲の符号付整数値
  • 範囲は環境によって異なる(32ビットのGHCなら32ビットの符号付整数値)

Integer

  • 表現範囲に制限のない整数値

浮動小数点数

  • Float
  • Double

Float

単精度(32ビット)の浮動小数点数

Double

倍精度(64ビット)の浮動小数点数

Rational

  • 有理数(二つの整数でa/b という分数で表せる数)を表す
  • import Data.Ratioでインポートする ※ 本ではRatioモジュールをインポートとあるが今はData.Ratioに移動したもよう
  • Rational型を表す場合はカッコをつけないエラーになる
Data.Ratio> toRational 0.5
1 % 2
Data.Ratio> fromRational (1 % 2)
0.5
Data.Ratio> fromRational 1 % 2
<interactive>:56:1:
    No instance for (Fractional a0) arising from a use of ‘it’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Integral a => Fractional (Ratio a)
        -- Defined in ‘GHC.Real’
      instance Fractional Double -- Defined in ‘GHC.Float’
      instance Fractional Float -- Defined in ‘GHC.Float’
    In the first argument of ‘print’, namely ‘it’
    In a stmt of an interactive GHCi command: print it

Complex

  • 複素数を表す
  • import Data.Complexでインポートする ※ 本ではComplexモジュールをインポートとあるが今はData.Complexに移動したもよう
コメント

複素数とはWikipedia によると

複素数(ふくそすう、complex number)は、実数 a, b と虚数単位 i を用いて a + bi と表せる数のことである。

とあるが、よくわからないのと使うことはないと思うので放置。(2乗するとマイナスになる値???)
→ 2乗するとマイナスになるのはiとのこと
→ 結論:『数学ガール』を読もう!

数学ガール (数学ガールシリーズ 1)

数学ガール (数学ガールシリーズ 1)

※ 色々でてるので、どれから読み始めればよいのかわからないが、とりあえず最初からか…

数値の演算

  • 演算する際に型が同じでなければならない
  • 自動で型変換は行われない
  • ただし文字リテラルのみの演算だと型推論が行われるので計算できる
> (1.0 :: Double) + (0.3 :: Float)

<interactive>:2:20:
    Couldn't match expected type ‘Double’ with actual type ‘Float’
    In the second argument of ‘(+)’, namely ‘(0.3 :: Float)’
    In the expression: (1.0 :: Double) + (0.3 :: Float)
    In an equation for ‘it’: it = (1.0 :: Double) + (0.3 :: Float)
> 1 + 0.3
1.3

加算(足し算)

備考
x + y

減算(引き算)

備考
x - y
abtract y x x - yとなる

乗算(掛け算)

備考
x * y

除算(割り算)

備考
x / y 結果は浮動小数点数となる
x div y 結果は割り算の整数部分。値は負の無限大向かってに丸められる。
x quot y 結果は割り算の整数部分。値は0に向かって丸められる。
x mod y x div y のあまり
x rem y x quot y のあまり
> 1/3
0.3333333333333333
> 12`div` 5
2
> (-12) `div` 5
-3
> 12`quot` 5
2
> (-12) `quot` 5
-2

その他の演算

備考
x ^ y x の y乗
abs x x の絶対値
odd x x が奇数ならTrue
even x x が偶数ならTrue

数値から別の数値への型変換

> :t toInteger
toInteger :: Integral a => a -> Integer
> :t toInteger
toInteger :: Integral a => a -> Integer
> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b

丸めの関数

関数 備考
ceiling x 切り上げ。マイナス値の場合は0に近い方になる。
floor x 切り捨て。マイナス値の場合は0に遠い方になる。
truncate x 切り捨て。マイナス値の場合は0に近い方になる。 ※ 本だと「trancate」になっているので注意
round x 四捨五入。マイナス値の場合は0に遠い方になる。
> :t ceiling
ceiling :: (Integral b, RealFrac a) => a -> b
> ceiling 1.3
2
> ceiling (-1.3)
-1
> :t floor
floor :: (Integral b, RealFrac a) => a -> b
> floor 1.5
1
> floor (-1.5)
-2
> :t truncate
truncate :: (Integral b, RealFrac a) => a -> b
> truncate 1.5
1
> truncate (-1.5)
-1
> :t round
round :: (Integral b, RealFrac a) => a -> b
> round 1.5
2
> round 1.4
1
> round (-1.5)
-2
> round (-1.4)
-1

文字と文字列

  • 文字はChar型
  • 文字コードUnicodeが使われる
  • Charを数値として扱うことはできない
  • 文字列は[Char]
  • String は[Char]の別名

タプル

  • 複数の型を持てるデータの塊
  • タプルは要素をカンマ区切りにし「()」でくくる
  • 1要素でなければ0要素でも複数要素を持つのも可能
  • 0要素のタプルはユニットと呼ばれる
  • 2つの要素はペアと呼ばれる

例:

(3, "aaaa") :: (Int, String)

zip関数

  • 2つのリストを1つのペア(タプル)のリストにする
  • リストの長さが一致しない場合は短いほうのリストの長さになる
> :t zip
zip :: [a] -> [b] -> [(a, b)]
> zip [1,2,3,4,5] ['a', 'b', 'c']
[(1,'a'),(2,'b'),(3,'c')]

unzip関数

  • ペアのリストを第1要素のリスト第2要素のリストの二つを持つリストを生成する
> :t unzip
unzip :: [(a, b)] -> ([a], [b])
> unzip [(1,'a'),(2,'b'),(3,'c')]
([1,2,3],"abc")

※ "abc"は[Char]

リスト

  • 同じ型の要素を格納するもの
  • 一方向のみで前から後ろにたどれるが逆は不可
  • リストは要素をカンマ区切りにし「[]」でくくる

:演算子

  • リストを生成する演算子
  • 要素 : リスト
  • 第1引数に要素、第2引数にリストをいれる
  • リストの最後は空のリスト
> :t (:)
(:) :: a -> [a] -> [a]
> 1 : 2 : 3 : []
[1,2,3]

リストの数列表記

  • ..を使って連番などを表現できる
  • 無限リストの場合は最後の要素を指定しない。例:[1..]
> [1..7]
[1,2,3,4,5,6,7]
> ['a'..'e']
"abcde"
> [1,3..11]
[1,3,5,7,9,11]

null関数

  • 空リストならTrue
> :t null
null :: Foldable t => t a -> Bool
> null [1,2,3]
False
> null []
True

リスト内包表記

  • map関数やfilter関数をあらわせる
  • 複数のリストとその要素もあつかえる
  • 汎用すると読みづらくなるので複雑なリスト内包表記は書かないほうが良い

map関数を表す場合

[ 要素の変数を使った式や関数 | 要素の変数 <- リスト ]

例:

> [x*2 | x <- [1,2,3]]
[2,4,6]

filter関数を表す場合

[ 要素の変数を使った式や関数 | 要素の変数 <- リスト, Boolの式 ]

例:

> [x*2 | x <- [1,2,3,4,5], (x `mod` 2) == 1]
[2,6,10]

複数のリストを扱う場合

> [(x,y)|x <- [1,2,3], y <-['a', 'b']]
[(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')]

catn.h

  • ファイルを読み込み内容を行番号をつけて標準出力するサンプル

zipLineNumberの定義

  • 引数に渡したリストから1から始まる数値とリストの要素のタプルにしたリストを生成
zipLineNumber :: [String] -> [(Int, String)]
zipLineNumber xs = zip [1..] xs

formatの定義

  • 行数と行を持つタプルを受け取り行数と行を合わせて1行にする
  • 行数は6文字の数日と前空白の文字列にする
  • 行数の文字列と行の間に空白をいれる
format :: (Int, String) -> String
format (n, line) = rjust 6 (show n) ++ " " ++ line
  • show nは数値を文字列にする
  • rjust 数値 文字列は" 文字列"という感じで引数の数値の文字数分の文字列にする関数

show関数

show :: (Show a) => a -> String
  • Show型の値を文字列変換する

練習問題

  • 答えに関しては特に問題はない
コメント
  • 「基本的な値」の章で関数が操作の論理的な結合順序の問題が出てくる意図がわからない。
    → 第8章で関数を扱ってるので、そこで出題するのならわかるが?