Haskell その7

Listあれこれ。

リストとインデックス

いつものごとく写経しながら動かしながら考える。

http://www.sampou.org/haskell/report-revised-j/list.html

elemIndex val list は、もしあれば、 list 中で最初にあらわれた val のインデックスを Just index として返す。 not (val `elem` list) であれば、 Nothing を返す。

写経。

t1 = elemIndex 3 [0..9]
t2 = elemIndex 100 [0..9]

動かす。

*Sample2> t1
Just 3
*Sample2> t2
Nothing

Justとはなんぞや?
elemIndexの型っていったい?…

*Sample2> :type t1
t1 :: Maybe Int

出た、Maybeモナド
噂には聞いてたけど<オイオイ
次の宿題は決まったな。ということで先へ。

http://www.sampou.org/haskell/report-revised-j/list.html

elemIndices val list は list 中にあらわれる val の出現に対応する インデックスをその順にならべたリストを返す。

写経。

t3 = elemIndices 3 [0,3,0,3,0,3,0]
t4 = elemIndices 9 [0,3,0,3,0,3,0]

動かす。

*Sample2> t3
[1,3,5]
*Sample2> t4
[]

こちらは見つからなかったら空のリストを返すのか。
ふーむ…。
elemIndexは要素が見つからなかったらいったい何を返すのか?
見つからなかったら-1を返す、なーんてそういう姑息なマネはしないわな。
要するにMaybeは例外のためなのかな?…。


つーか、-1のインデックスを指定して要素を取り出すとどーなる?
…がーん、val = list[index] のようなイディオムがわかんない。

http://www.sampou.org/haskell/report-revised-j/list.html

and what the Prelude exports

標準プレリュードにある?

http://www.sampou.org/haskell/report-revised-j/standard-prelude.html
これっぽいですね。

(!!)                :: [a] -> Int -> a
xs     !! n | n < 0 =  error "Prelude.!!: negative index"
[]     !! _         =  error "Prelude.!!: index too large"
(x:_)  !! 0         =  x
(_:xs) !! n         =  xs !! (n-1)

やって見る。

*Sample2> [0..9]!!(-1)
*** Exception: Prelude.(!!): negative index

む、こちらはあからさまな例外処理。
Haskellの例外処理も宿題だな。
次いこ。

http://www.sampou.org/haskell/report-revised-j/list.html

find は述語を満す最初の要素を返す。もし、見つからない場合 には Nothing を返す。findIndex は対応 するインデックスを返す。findIndices はそのようなすべての インデックスのリストを返す。

写経。

f1 x | x > 0     = True
     | otherwise = False
t5 = find f1 [-1,-2,-3,0,1,2,3]
t6 = findIndex f1 [-1,-2,-3,0,1,2,3]
t7 = findIndices f1 [-1,-2,-3,0,1,2,3]

動かす。

*Sample2> t5
Just 1
*Sample2> t6
Just 4
*Sample2> t7
[4,5,6]

もう驚かない。
だいたい期待どおりだ。

集合演算

http://www.sampou.org/haskell/report-revised-j/list.html

nub はリストのから要素の重複をとりのぞく。

delete x はそのリスト引数から最初に出現した x を取り除く。

写経。

t8 = nub [0,0,0,1,3,2,3,2,2,2,3,3,0,1,1,1]
fparity x y = (x `rem` 2) == (y `rem` 2)
t9 = nubBy fparity [0,0,0,1,3,2,3,2,2,2,3,3,0,1,1,1]
t10 = delete 3 [0,0,0,1,3,2,3,2,2,2,3,3,0,1,1,1]
t11 = deleteBy fparity 3 [0,0,0,1,3,2,3,2,2,2,3,3,0,1,1,1]

これらもなんとなく素直そう。動かす。

*Sample2> t8
[0,1,3,2]
*Sample2> t9
[0,1]
*Sample2> t10
[0,0,0,1,2,3,2,2,2,3,3,0,1,1,1]
*Sample2> t11
[0,0,0,3,2,3,2,2,2,3,3,0,1,1,1]

あ、ウソ。
Byが付く関数が分からない。

http://www.sampou.org/haskell/report-revised-j/list.html

慣例でいうと、多重定義関数には、"By" 接尾辞のついた、 非多重定義関数版がある。例えば、関数 nub は以下のように 定義されている。

nub :: (Eq a) => [a] -> [a]
nub =
nub (x:xs) = x : nub (filter (\y -> not (x == y)) xs)

しかし、同等性メソッドはすべての状況で適切であるとは限らない。 次の関数

nubBy :: (a -> a -> Bool) -> [a] -> [a]
nubBy eq =
nubBy eq (x:xs) = x : nubBy eq (filter (\y -> not (eq x y)) xs)

ではプログラマが同等性テストを独自に与えることができる。 "By" 関数が、Eq 文脈を二項述語で置き換えた場合、 この述語は同等性を定義するものと仮定される。"By" 関数が Ord 文脈を二項述語で置き換えた場合、この述語は全順序を 定義しているものと見なす。

うー、寝る前にこういうの考えるのは厳し〜。
また明日じっくり理解しよう。

なんだか今日は宿題が多いな。