Haskell
線形代数

行列プログラマ in Haskell

More than 1 year has passed since last update.

行列プログラマに登場するPythonをひたすらHaskellでかいてく。対応するPythonコードは書籍にて確認いただきたい。

0.4.1 確率分布

> import Data.Map
> fromList [("heads", 1/2), ("tail", 1/2)] 
fromList [("heads", 1/2), ("tail", 1/2)]
  :: Fractional a => Map [Char] a

Pythonの辞書型に相当するものは Data.Mapかな。
他だいたい同じなので省略。

0.5.1 簡単な式

> 44 + 11 * 4 - 6 / 11
87.45454545454545

課題 0.5.1: Python を使用して、1 週間が何秒かを求めよ

> 7 * 24 * 60 * 60
604800

課題 0.5.2: Python を使用して、2304811 を 47 で割った余りを求めよ。ただし、% を使用しないこ と(ヒント://を用いる)。

> (\y x -> y - (y `div` x) * x) 2304811 47
25

% の代わりとしては remがある

文字列

> "This sentence is false."
"This sentence is false."

比較、条件、ブール値

> 5 == 4
False
> 4 == 4
True

haskellだとブール演算は && || not

> True && False
False
> True && not (5 == 4)
True

課題 0.5.3: ブール式を入力して、673 と 909 の和が 3 で割り切れるかどうかを調べよ。

問題の意味がわからず。。。省略

ghci内であれば :t で値の方を調べられる

> :t 4
4 :: Num t => t
> :t 4 == 4
4 == 4 :: Bool
> :t 
"4" :: [Char]
> :t 4 :: Float
4 :: Float

4の型は IntやFloatなど数字で扱える型になれることを出力している。
4をFloatとして使いたいなら型注釈をつければよい。

0.5.2 代入文

> mynum = 4+1

Haskellでは普通は再代入不可能だがghci上だと可能

> mynum = "Brow"

0.5.3 条件式

Haskellのifはelseが必須になる。

課題 0.5.4: −9 を x に、1/2 を y に代入する。以下の式の値を予想し、入力して予想を確認せよ。 2*(y+1/2) if x+10<0 else 2*(y-1/2)

条件は false 2 ** 0 で 1

> (\x y -> if x + 10 < 0 then 2**(y+1/2) else 2**(y-1/2)) (-9  :: Int) (1/2)
1.0

0.5.4 集合

> import Data.Set
> fromList [1+2, 3, 4]
fromList [3,4]

集合を表現するなら Data.Set

3が重複するのでひとつになってる。"a"は型が違うのでこのままでは一緒の集合にはできない。

> import Data.Set
> length(fromList ['a','b','c','a','c'])
3

濃度はlengthで取得できる。

集計

> import Data.Set
> sum(fromList [1,2,3])
6

集合の要素のテスト

> import Data.Set
> member 3 (fromList [1,2,3])
True
> member 4 (fromList [1,2,3])
False
> 4 `member` (fromList [1,2,3])
False
not . 4 `member` $ (fromList [1, 2, 3])
> True

集合の和集合、共通部分、差集合

> (fromList [1,2,3]) `union` (fromList [2,3,4])
fromList [1,2,3,4]
> (fromList [1,2,3]) `intersection` (fromList [2,3,4])
fromList [2,3]
> (fromList [1,2,3]) `difference` (fromList [2,3,4])
fromList [1]

集合の変更

> delete 2 . insert 4 . fromList $ [1,2,3]

fromList [1,3,4]

集合の内包表記

Setはモナドではななそうなので内包表記できそうにない。

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

課題 0.5.5: 集合 {1, 2, 3, 4, 5} に対する内包表記で、それぞれの整数の 2 乗を返すものを書け。

> fromList [x*x | x <- [1..5]]
fromList [1,4,9,16,25]

課題0.5.6: 集合{0,1,2,3,4}に対する内包表記で、それぞれの整数を2の指数に持つ値、即ち、20、 21、22 などを返すものを書け。

> fromList [2 ^ x | x <- [0..4]]
fromList [1,2,4,8,16]

> fromList [x*x | x <- toList (fromList [1,3] `union` (fromList [5,7]))]
fromList [1,9,25,49]
> fromList [x*x | x <- toList (fromList [1,3] `union` (fromList [5,7])), x > 2]
fromList [9,25,49]
> fromList [x*y | x <- [1..3] , y <- [2..4]]
fromList [2,3,4,6,8,9,12]

課題 0.5.7

> fromList [x*y | x <- [1..3] , y <- [5,7,11]]
fromList [5,7,10,11,14,15,21,22,33]

> fromList [x*y | x <- [1..3] , y <- [2..4], x /= y]
fromList [2,3,4,6,8,12]

課題 0.5.8

> fromList [x*y | x <- [2,4,8] , y <- [3,6,12]]
fromList [6,12,24,48,96]

課題 0.5.9

> [x | x <- [1,2,3,4] , y <- [3,4,5,6], x == y ]
[3,4]

0.5.5 リスト

> [1,1+1,3,2,3]
[1,2,3,2,3]

Haskellのリストの要素には制限があるのでHlistとか使うか、型を用意するかしないといけない。


> sum [1,1,0,1,0,1,0]
4
> foldl (+) (-9) [1,1,0,1,0,1,0]
-5

Haskellのsumに第2引数はないのでfoldlでかいてみた

0.5.10 評価した値がリスト [20,10,15,75] の要素の平均となる式を書け。

> (\xs -> sum xs / (fromIntegral . length $ xs)) [20,10,15,75]
30.0

求める結果が浮動小数になるように fromIntegralをつかっています。

リストの結合

++ で結合可能だけど、効率はいまいち

> [1,2,3] ++ [4,5]
[1,2,3,4,5]
> let mylist = [4,8,12]
> mylist ++ [4,5]
[4,8,12,4,5]
> mylist
[4,8,12]
> [[1,2,3], [4,5,6],[7,8,9]]

文字列と数値が混ざったリストはつくれないので数字だけにした。


すべてのリストを結合するのはsumではできないのでfoldMapをつかった。

> foldMap id [[1,2,3], [4,5,6],[7,8,9]]
[1,2,3,4,5,6,7,8,9]

リストの内包表記

> [2*x | x <- [2,1,3,4,5]]
[4,2,6,8,10]
>  [x*y | x <- [1,2,3] ,y <- [10,20,30]]
[10,20,30,20,40,60,30,60,90]

課題 0.5.11: リスト [’A’,’B’,’C’] 及び [1,2,3] に対するリスト内包表記で、その値が [文 字, 数字] の全ての可能な組み合わせから成るものを書け。即ち、その値は以下のようなものである。

[[’A’, 1], [’A’, 2], [’A’, 3], [’B’, 1], [’B’, 2],[’B’, 3],
[’C’, 1], [’C’, 2], [’C’, 3]]

> [(x,y) | x <- ['A', 'B', 'C'], y <- [1,2,3]]
[('A',1),('A',2),('A',3),('B',1),('B',2),('B',3),('C',1),('C',2),('C',3)]

課題 0.5.12: LofL に数字のリストを要素に持つリストを代入したとしよう。このとき、そのリス ト全ての数値全部を足した合計を計算する式を書け。この式は次の形を持ち、内包表記を 1 つ持つ

> (\lofl -> sum [sum x| x <- lofl]) [[0.25, 0.75, 0.1], [-1,0], [4,4,4,4]]
16.1

インデックス指定によるリストの要素の取得

> let mylist = [1..4]
> mylist !! 0
1
> ["in", "the", "CI"] !! 1
"the"
> let l = [0,10..90]
> take 5 l
[0,10,20,30,40]
> drop 5 l
[50,60,70,80,90]
> map fst . filter (even . snd) $ zip l [0..]
[0,20,40,60,80]
> map fst . filter (odd . snd) $ zip l [0..]
[10,30,50,70,90]

スライスするいい方法がおもいうかばず。

アンパックによるリストの要素の取得

パターンマッチで代用

>  case [4*1, 4*2, 4*3] of [a,b,c] -> print a >> print b >> print c
4
8
12

リストの変更: =の左辺でのインデックス指定

Haskellでは原則リストの変更はできない。
再生成するしかないが効率は微妙なので、ここではおいておく。

0.5.6 タプル

> (1, 1+1, 3)
(1, 2, 3)

TBD

1.2 Pythonにおける複素数

Haskellで複素数をつかうには Data.Complexをimportする。
https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Complex.html

> import Data.Complex
> 0 :+ 3      -- 3j
> (0 :+ 3) * (0 :+ 3)
(-9.0) :+ 0.0
> import Data.Complex
> 1 :+ 3
> import Data.Complex
> (1 :+ 3) + (10 :+ 20)
11.0 :+ 23.0
> x = 1 :+ 3
> (x-1) ^ 2
(-9.0) :+ 0.0

Haskellの累乗計算の演算子は ^** がある
^が整数要で、**が浮動小数点要である

:++の優先順位は同じなので、注意

> 1 :+ 2 * 3
1 :+ 6
> 4*(0:+3)^^2
(-36.0) :+ 0.0

0:+とかくのがすこしめんどくさい

実部と虚部のとりだし

> realPart (1 :+ 3)
1
> imagePart (1 :+ 3)
3

型の確認

> :t (1:+2)
(1:+2) :: Num a => Complex a