行列プログラマに登場する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