SlideShare ist ein Scribd-Unternehmen logo
1 von 49
Downloaden Sie, um offline zu lesen
すごい配列楽しく学ぼう
     ~ Haskell の配列事情 ~
           @xenophobia__




        
テーマについて
勉強会をやるらしい
→ 各 λ 人の好きな題材でいいらしい。
→ じゃあ Haskell で何か話そう。
→ でもすごい H 本出たし基本的なことはもう話題と
 して出尽してるよな……
→ あれ?この本配列について書いてなくね?
→ λ < Haskell の配列も楽しく学ぼう!



              
Haskell とは!
   なんてことを話している時間はない。
   とりあえず今後の話に関わることとしてこれぐらい。
            型に厳しい(強い静的型付けである)
                  キャストとかゆとりな事はしない
                  型が合ってないと絶対許してくれない
            参照透明性が(基本的には)成り立つ
                  IO ・破壊的変更の扱いがめんどい特殊
                  unsafe ほげほげの話はしない
            「型クラス」がある
                  「型クラス」は共通の性質を持った型の集まり
                  ある型クラスに関して polymorphic な関数とか書ける
                         
Haskell の配列について
   Haskell では、コレクションは普通リスト型で扱う。
   配列はあんまり話題にならない気がする(すごい H
     本にも記述は多分ない? RHW にはあった)
   調べるといろいろ (Array, UArray, IArray, MArray, 
     IOArray, ...) でてきてよくわからない。


   でも……
             プロコンとかだと使いたい。
             できるだけ速いほうがいい。
                     
Agenda
   とりあえず普通の配列( Array, UArray )
   O(1) で変更できなきゃ配列じゃない! (IOArray, 
     IOUArray)
   型クラスの話をしよう (IArray, MArray)




                 
Agenda
   とりあえず普通の配列( Array, UArray )
   O(1) で変更できなきゃ配列じゃない! (IOArray, 
     IOUArray)
   型クラスの話をしよう (IArray, MArray)




                 
Haskell 標準の配列を使う
   Array, UArray (違いはあとで。)
   Array は Data.Array( または Data.Array.IArray) に
     ある。
   UArray は Data.Array.Unboxed にある。




                    
Haskell 標準の配列を使う
   配列を作るには?
    → array 関数を使う(或いは listArray )
             array (0, 3) [(0, 1), (1, 2), (2, 4), (3, 9)]
             array ((1, 1), (2, 2)) [((1,1), 'a'), ((1,2), 'a'), ((2,1), 'z'), 
                ((2,2), 'd')]
             listArray (1, 100) [0, 0 ..]
   インデックスには、 Int, Char 及びそのタプルなどが
     使える。
                       厳密には Ix 型クラスのインスタンスがすべて使える。
                         ここでは説明は省略。
                                 
Haskell 標準の配列を使う
   型は?
   C などと違い、インデックスもいろいろ使える。
      → インデックスも型パラメタとして与える。
   インデックスが Int で要素が String の Array なら、
     Array Int String  となる。
   インデックスが (Char, Char) で要素が Int の
     UArray なら、 UArray (Char, Char) Int となる。



                    
Haskell 標準の配列を使う
   配列 ary の要素にアクセスしたい → (!) 演算子
             例) let x = ary!2 in …
                     let x = ary!(0, 3) in …
   配列 ary の要素を更新したい → (//) 演算子
             例) let ary' = ary//[(1, 2), (3, 0)]
                     ­­ ary[1] を 2 に、 ary[3] を 0 に更新
             ただし、これには後に述べるように罠が隠れている。




                               
Array/UArray の違いって?
   Array 型と UArray 型は、使い方はほぼ同じ。
   じゃあ違いは?
             Array は Box 化されている
             Uarray は Box 化されていない


   (´ ・ _ ・ `) ? < おまえは なにを いってるんだ




                        
Array/UArray の違いって?
   つまり
            Array は、オブジェクトへのポインタを持った配列
            UArray は、値そのものを入れる配列
   もっと言うと
            Array は Lazy な配列
            UArray は Strict な配列




                         
Array/UArray の違いって?
   Array の要素を参照するときの動作
   ポインタが示す先に行き、オブジェクトを返す
               そのオブジェクトの値が必要になったら評価する。
               もちろん、オブジェクトが評価済みならその値自体を
                 返す。
    0

    1                     未評価              評価済み
                                    Eval
    2
                          10 * 10           100
    3




                       
なんでそんなことになってんの?
   知らん。




            
なんでそんなことになってんの?
   …… ではさすがにあんまりなので。


   Array が正格評価する仕様だと、例えば変数 x, y, 
     z を用いて
          ary = array (1, 3) [(1, x), (2, y), (3, z)]
    のようにに配列を作ると、 x, y, z は配列作成時に
     全て評価されなければならない。(評価しないと
     格納する値がわからない)


                           
なんでそんなことになってんの?
   「 x を配列に入れる」というロジックに「 x を評価す
      る」ことは必要か?
   たとえば ary のうち一つの要素にしかアクセスしな
     いかもしれない。
    → 「アクセスしない=使わない」ってことじゃない
     の?




               
なんでそんなことになってんの?
   λ <使わないのに評価されるのは遅延評価とし
     ておかしい!( Haskell は call by need の遅延評
     価!)
   要素が何であるかの評価は、実際にその要素の値
     が必要になるまで遅延するのがよい!
               てな感じなんじゃないですかね。知らんけど……




                  
UArray(Unboxed Array)
   Q. じゃあ UArray って何?
   A. Array 遅い!って人のために。


   UArray はポインタを介さない分 Array よりアクセ
     スが速い&場所とらない。
   速さとヒープ領域を気にするならこっち使いましょ
     う。



                  
Agenda
   とりあえず普通の配列( Array, UArray )
   O(1) で変更できなきゃ配列じゃない! (IOArray, 
     IOUArray)
   型クラスの話をしよう (IArray, MArray)




                 
「 Array と参照透明性」
             に関する孔明の罠
   さっき (//) という「更新」演算子がでてきた。
   でも、 Haskell の関数は(基本的には)参照透明性
     が成り立ってなければならない。
   参照透明性 : 関数と引数の組によって、返り値が
     一意に決まる。




               
「 Array と参照透明性」
                     に関する孔明の罠
   つまり?
   ary = array (1, 2) [(1, 1), (2, 2)]
    として、
               ary!1
               let ary' = ary//[(1, 2)] in
                  ary!1
   は同じ値であってほしいなければならない。



                                 
「 Array と参照透明性」
              に関する孔明の罠
   しかし、 ary を破壊的に更新してしまった場合、
     ary!1 が元の値を返すかどうかはわからない。
     ary!1 が更新前に評価されれば 1 が返り、
     ary!1 が更新後に評価されれば 2 が返る。
          → 参照透明性に反する!
          ary!1 はいつ評価しても同じ値を返さなければなら
            ない。




                  
「 Array と参照透明性」
             に関する孔明の罠
   じゃあどういう実装になってんの?
     → 単純に、 ary には変更を加えず
     ary' 用の配列を新しく作る。
     → これでどこをいつ参照しても矛盾は起きない。
     やったね(?)




               
「 Array と参照透明性」
                 に関する孔明の罠
   …… なにもうまくいってません。
            問題 1 :そもそも「更新」じゃなくて「新規作成」演算
              子になってる
            問題 2 :計算量 O(sizeof(ary))
              →  プロコンでうっかり使ったりすると死ぬ
   結論: (//) は更新する演算子ではなく、更新され
     た配列を新規作成する演算子




                     
補足
   注 1 )ドキュメントにも Incremental array updates
     と書いてあってまぎらわしい。
   注 2 ) Data.Array.IArray には、「殆どの IArray の
     インスタンスにおいて更新には O(N) かかる」と
     書いてある。
   注 3 ) Data.Array.IArray の (//) 関数の仕様自体が
     O(N) の計算量に本質的に関わっているわけで
     はない。(実際、もっと速い更新を実現する
     DiffArray などの IArray インスタンスもある)

                   
うまい解決法はないか
   破壊的更新ができれば文句ない。
   Haskell で破壊的操作をうまく扱う方法として IO
     モナドがある。
   IO モナドの文脈中ならうまいこと破壊的操作を扱
      える。
    → IO モナドの中でしか使えない配列を作れば万
     事解決!




               
IOArray/IOUArray
   Data.Array.IO にどっちも定義されている。
   作成・参照・更新は全て IO アクション。
     → アクションの実行順序は保証されるので、参
     照と更新の順序が入れかわったりしない!




                
IOArray/IOUArray
   作成: newArray(newArray_, newListArray)
              newArray (lb, ub) x  で、インデックスが lb 〜 ub の
                 x で初期化された配列を返すアクションを返す。
   参照: readArray
              readArray ary i で、 ary の i 番地の値を返すアクショ
                 ンを返す。
   更新: writeArray
              writeArray ary i x で、 ary の i 番地の値を x に変更
                するアクションを返す。

                           
IOArray/IOUArray
   使い方
   IO モナドの中で使う。
             do ary ← newArray (1, 10) 0
                  x ← readArray ary 1
                  writeArray ary 1 3
                  y ← readArray ary 1
                  ...
   x, y  には 0, 3 がそれぞれ束縛される。



                            
参照透明性は?
   さっきのプログラムの 2 つの readArray ary 1 って
     別々の値を返してね?
     → readArray ary 1 はあくまで両方「 ary からイン
     デックス i の値を取り出す操作」を表すアクション
     なのであって、 x, y を返す関数ではありません。




                 
Pros & Cons
   正真正銘の O(1) 更新が可能!
   ただ、 IO に汚染される上、インタフェースが多少め
     んどい。




              
備考
   IOArray 以外にも、 STArray など破壊的代入がで
      きる配列はある。
   IO モナドと違い ST モナドは外に脱出できるの
      で、 IO 操作を他に使わないならこっちのほうが
      いいかも。
             IOArray と使い勝手は一緒




                       
補足( 1 )
   thaw/freeze 関数を用いて普通の配列と可変配列
      との相互変換もできる。
   thaw (解凍)が Immutable → Mutable の変換
   freeze (凍結)が Mutable → Immutable の変換




                  
補足( 2 )
   もちろん thaw も freeze も O(N) 。
              ドキュメントにもちゃんと” by taking a complete copy 
                of it.” とある。
   こういうときこそ STArray 使うといいかもしれない。
              手前味噌ですが STUArray を用いたエラトステネス
                の篩実装例
                http://d.hatena.ne.jp/g940425/20110827/1314442246
                      後半で unsafe な関数使ってるけど……こういう使い
                        かたなら問題ないはず。



                             
Agenda
   とりあえず普通の配列( Array, UArray )
   O(1) で変更できなきゃ配列じゃない! (IOArray, 
     IOUArray)
   型クラスの話をしよう (IArray, MArray)




                 
抽象化したい!
   Uarray と Array 、 IOUArray と IOArray は Box 化 /
     非 Box 化の違いでしかない。
     → これらの違いを無視した一般的なインタ
     フェースの関数を書きたい。




                    
例えば……




   sumA : Int 要素を持つ Array の全要素の和



                
例えば……




   sumA をそのまま UArray に使おうとすると、当然の
      ように型エラーで怒られる。


               
例えば……




   型ごとに関数を用意すればお k !



              
いやいや
      <「お k !」じゃねえ!
       関数本体全く同じじゃねえか!
   こういう、形がほとんど同じ関数を連ねるのを
     「ボイラープレート( boilerplate )」という
     → Haskeller が最も嫌うもの
                   私も大嫌いです



   形が同じなら、まとめてかけるはず



                
IArray/MArray
   変更不可配列 (Immutable Array) を抽象する型ク
     ラスが IArray
   可変配列 (Mutable Array) を抽象する型クラスが
     MArray
   型クラス: Iarray/MArray はそれ自体「型」ではな
     い( IArray  〜 型の値、は存在しない)




                
IArray/MArray
   IArray a e : e 型の要素を持つ変更不可配列 a
   Marray a e m : m モナドのコンテクストで変更可能
     な、 e 型の要素を持つ配列 a




                
例ふたたび




   IArray を使って sumA を抽象化
   GHC 拡張 FlexibleContexts が必要(理由は後述)


                 
例ふたたび
   sumA :: IArray a Int => …
    → 「 a が Int を要素に持つ変更不可配列」
     という型制約をかけている
   sumA :: … => a Int Int → Int
      → a Int Int → Int という型を持つので、
      a として当てはまる(= IArray a Int というインス
      タンスが宣言されている)もの全てに適用可能




                      
例ふたたび
   Data.Array.IArray にインスタンスとして
             IArray Array e
             IArray UArray Int
    が宣言されている。( e は型変数で、なんでもよい)
     → a が Array でも UArray でも型が合う!
             IArray Array Int => Array Int Int → Int
               OK !:インスタンス IArray Array e がある


             IArray UArray Int => UArray Int Int → Int
               OK !:インスタンス IArray UArray Int がある



                              
補足( 3 )
   Q. かける制約は IArray a e でよかったのでは?
   A. 実は、 IArray UArray e という要素の型 e につい
     て一般化されたインスタンスはない。
     (Data.Array.UArray のドキュメント参照)
     → なのでこの例では IArray a Int のインスタンス
     宣言を使っており、そのため制約が IArray a Int
     となっている。
             IArray Array e => Array Int Int → Int
               OK !:インスタンス IArray Array e がある


             IArray UArray e => UArray Int Int → Int
               NG !:インスタンス IArray UArray e はない
                             
補足( 4 )
   本来、型制約に具体的な型を入れることはできな
     い。
     → IArray a Int という制約はふつう許されない。
   これを許可するのが FlexibleContexts 拡張




                 
総括
   Haskell でも普通に配列使える
   しかし、速いプログラムにするには工夫が要る
     →使えるところでは Unboxed な配列を使う、とか
   抽象化もできる
     → ただ、なんでもかんでも抽象化すればいいと
     いうわけじゃない。 Lazy/Strict が本質的な場面
     もあるだろうし、競技プログラミングでわざわざ
     使いもしないのに抽象化した関数を書くのは得
     策でない。


               
より進んだ話題
   Haskell には並列処理用行列
     repa ( [hackage]http://hackage.haskell.org/packa
     ge/repa )という、データ並列プログラミングをサ
     ポートする特殊なライブラリもある。
     → 配列というよりは「行列」
     → ついこの間( 2012/9/24 ) GHC­7.6 にも対応
   DiffArray なんてのもある( Immutable かつ更新も
     それなりに速い)
     [hackage]http://hackage.haskell.org/package/diffa
     rray

                      

Weitere ähnliche Inhalte

Was ist angesagt?

RSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjpRSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjpsonickun
 
ユークリッド最小全域木
ユークリッド最小全域木ユークリッド最小全域木
ユークリッド最小全域木理玖 川崎
 
色々なダイクストラ高速化
色々なダイクストラ高速化色々なダイクストラ高速化
色々なダイクストラ高速化yosupo
 
Rolling Hashを殺す話
Rolling Hashを殺す話Rolling Hashを殺す話
Rolling Hashを殺す話Nagisa Eto
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みMasahiro Sakai
 
Visual Studio CodeでRを使う
Visual Studio CodeでRを使うVisual Studio CodeでRを使う
Visual Studio CodeでRを使うAtsushi Hayakawa
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門Hideyuki Tanaka
 
プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法Takuya Akiba
 
論理と計算のしくみ 5.3 型付きλ計算 (前半)
論理と計算のしくみ 5.3 型付きλ計算 (前半)論理と計算のしくみ 5.3 型付きλ計算 (前半)
論理と計算のしくみ 5.3 型付きλ計算 (前半)Lintaro Ina
 
充足可能性問題のいろいろ
充足可能性問題のいろいろ充足可能性問題のいろいろ
充足可能性問題のいろいろHiroshi Yamashita
 
自動定理証明の紹介
自動定理証明の紹介自動定理証明の紹介
自動定理証明の紹介Masahiro Sakai
 
勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとはTakuya Akiba
 
数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013Shuyo Nakatani
 
Introduction to Categorical Programming (Revised)
Introduction to Categorical Programming (Revised)Introduction to Categorical Programming (Revised)
Introduction to Categorical Programming (Revised)Masahiro Sakai
 

Was ist angesagt? (20)

双対性
双対性双対性
双対性
 
RSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjpRSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjp
 
ユークリッド最小全域木
ユークリッド最小全域木ユークリッド最小全域木
ユークリッド最小全域木
 
色々なダイクストラ高速化
色々なダイクストラ高速化色々なダイクストラ高速化
色々なダイクストラ高速化
 
Binary indexed tree
Binary indexed treeBinary indexed tree
Binary indexed tree
 
Rolling Hashを殺す話
Rolling Hashを殺す話Rolling Hashを殺す話
Rolling Hashを殺す話
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
 
Visual Studio CodeでRを使う
Visual Studio CodeでRを使うVisual Studio CodeでRを使う
Visual Studio CodeでRを使う
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法
 
論理と計算のしくみ 5.3 型付きλ計算 (前半)
論理と計算のしくみ 5.3 型付きλ計算 (前半)論理と計算のしくみ 5.3 型付きλ計算 (前半)
論理と計算のしくみ 5.3 型付きλ計算 (前半)
 
Rolling hash
Rolling hashRolling hash
Rolling hash
 
充足可能性問題のいろいろ
充足可能性問題のいろいろ充足可能性問題のいろいろ
充足可能性問題のいろいろ
 
最大流 (max flow)
最大流 (max flow)最大流 (max flow)
最大流 (max flow)
 
Chokudai search
Chokudai searchChokudai search
Chokudai search
 
自動定理証明の紹介
自動定理証明の紹介自動定理証明の紹介
自動定理証明の紹介
 
圏とHaskellの型
圏とHaskellの型圏とHaskellの型
圏とHaskellの型
 
勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは
 
数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013
 
Introduction to Categorical Programming (Revised)
Introduction to Categorical Programming (Revised)Introduction to Categorical Programming (Revised)
Introduction to Categorical Programming (Revised)
 

Andere mochten auch

Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料時響 逢坂
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料時響 逢坂
 
Windows 8 UX Guidelines
Windows 8 UX GuidelinesWindows 8 UX Guidelines
Windows 8 UX GuidelinesTakaaki Suzuki
 
すごいHaskell読書会 第六章 発表資料
すごいHaskell読書会 第六章 発表資料すごいHaskell読書会 第六章 発表資料
すごいHaskell読書会 第六章 発表資料Hiromasa Ohashi
 
ウォーキングとゆっくり呼吸のすごい効果
ウォーキングとゆっくり呼吸のすごい効果ウォーキングとゆっくり呼吸のすごい効果
ウォーキングとゆっくり呼吸のすごい効果Shu Takeda
 
【アップロードテスト】データマイニング入門編_201501
【アップロードテスト】データマイニング入門編_201501【アップロードテスト】データマイニング入門編_201501
【アップロードテスト】データマイニング入門編_201501takosumipasta
 
すごいVimでhaskellを書こう@なごやまつり
すごいVimでhaskellを書こう@なごやまつりすごいVimでhaskellを書こう@なごやまつり
すごいVimでhaskellを書こう@なごやまつりcohama
 
プラグインだけじゃない!そのままでもすごいvim
プラグインだけじゃない!そのままでもすごいvimプラグインだけじゃない!そのままでもすごいvim
プラグインだけじゃない!そのままでもすごいvimKeisuke Izumiya
 
「360°スゴイ」を創るVOYAGE GROUPエンジニア成長施策
「360°スゴイ」を創るVOYAGE GROUPエンジニア成長施策「360°スゴイ」を創るVOYAGE GROUPエンジニア成長施策
「360°スゴイ」を創るVOYAGE GROUPエンジニア成長施策Hironori Miura
 
Globalization Of Health Care Final Star
Globalization Of Health Care Final StarGlobalization Of Health Care Final Star
Globalization Of Health Care Final StarHerman D. Smith
 
すごいタスク管理(仮)
すごいタスク管理(仮)すごいタスク管理(仮)
すごいタスク管理(仮)Kakigi Katuyuki
 
altJS勉強会「Haxeすごいからみんな使え!」
altJS勉強会「Haxeすごいからみんな使え!」altJS勉強会「Haxeすごいからみんな使え!」
altJS勉強会「Haxeすごいからみんな使え!」政樹 尾野
 
このIRのグラフがすごい!上場企業2015
このIRのグラフがすごい!上場企業2015このIRのグラフがすごい!上場企業2015
このIRのグラフがすごい!上場企業2015itoyan110
 

Andere mochten auch (20)

Xenophobia
XenophobiaXenophobia
Xenophobia
 
Xenophobia
XenophobiaXenophobia
Xenophobia
 
Xenophobia Talk
Xenophobia TalkXenophobia Talk
Xenophobia Talk
 
Diff
DiffDiff
Diff
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料
 
Windows 8 UX Guidelines
Windows 8 UX GuidelinesWindows 8 UX Guidelines
Windows 8 UX Guidelines
 
Xenophobia 2
Xenophobia 2Xenophobia 2
Xenophobia 2
 
すごいHaskell読書会 第六章 発表資料
すごいHaskell読書会 第六章 発表資料すごいHaskell読書会 第六章 発表資料
すごいHaskell読書会 第六章 発表資料
 
ウォーキングとゆっくり呼吸のすごい効果
ウォーキングとゆっくり呼吸のすごい効果ウォーキングとゆっくり呼吸のすごい効果
ウォーキングとゆっくり呼吸のすごい効果
 
Yesod勉強会
Yesod勉強会Yesod勉強会
Yesod勉強会
 
INTERCULTURAL COMMUNICATION COMPETENCE
INTERCULTURAL COMMUNICATION COMPETENCEINTERCULTURAL COMMUNICATION COMPETENCE
INTERCULTURAL COMMUNICATION COMPETENCE
 
【アップロードテスト】データマイニング入門編_201501
【アップロードテスト】データマイニング入門編_201501【アップロードテスト】データマイニング入門編_201501
【アップロードテスト】データマイニング入門編_201501
 
すごいVimでhaskellを書こう@なごやまつり
すごいVimでhaskellを書こう@なごやまつりすごいVimでhaskellを書こう@なごやまつり
すごいVimでhaskellを書こう@なごやまつり
 
プラグインだけじゃない!そのままでもすごいvim
プラグインだけじゃない!そのままでもすごいvimプラグインだけじゃない!そのままでもすごいvim
プラグインだけじゃない!そのままでもすごいvim
 
「360°スゴイ」を創るVOYAGE GROUPエンジニア成長施策
「360°スゴイ」を創るVOYAGE GROUPエンジニア成長施策「360°スゴイ」を創るVOYAGE GROUPエンジニア成長施策
「360°スゴイ」を創るVOYAGE GROUPエンジニア成長施策
 
Globalization Of Health Care Final Star
Globalization Of Health Care Final StarGlobalization Of Health Care Final Star
Globalization Of Health Care Final Star
 
すごいタスク管理(仮)
すごいタスク管理(仮)すごいタスク管理(仮)
すごいタスク管理(仮)
 
altJS勉強会「Haxeすごいからみんな使え!」
altJS勉強会「Haxeすごいからみんな使え!」altJS勉強会「Haxeすごいからみんな使え!」
altJS勉強会「Haxeすごいからみんな使え!」
 
このIRのグラフがすごい!上場企業2015
このIRのグラフがすごい!上場企業2015このIRのグラフがすごい!上場企業2015
このIRのグラフがすごい!上場企業2015
 

Ähnlich wie すごい配列楽しく学ぼう

BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
scala.collection 再入門 (改)
scala.collection 再入門 (改)scala.collection 再入門 (改)
scala.collection 再入門 (改)Ryuichi ITO
 
Scala勉強会
Scala勉強会Scala勉強会
Scala勉強会omi end
 
Equality in Scala (ScalaMatsuri 2020)
Equality in Scala (ScalaMatsuri 2020)Equality in Scala (ScalaMatsuri 2020)
Equality in Scala (ScalaMatsuri 2020)Eugene Yokota
 
Javaプログラミング入門【第7回】
Javaプログラミング入門【第7回】Javaプログラミング入門【第7回】
Javaプログラミング入門【第7回】Yukiko Kato
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜Hiromi Ishii
 
RSpecのここがすごい!
RSpecのここがすごい!RSpecのここがすごい!
RSpecのここがすごい!mitim
 
ゆるふわScalaコップ本読書会 第7章
ゆるふわScalaコップ本読書会 第7章ゆるふわScalaコップ本読書会 第7章
ゆるふわScalaコップ本読書会 第7章Yuta Yokoi
 

Ähnlich wie すごい配列楽しく学ぼう (12)

BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
scala.collection 再入門 (改)
scala.collection 再入門 (改)scala.collection 再入門 (改)
scala.collection 再入門 (改)
 
Scala勉強会
Scala勉強会Scala勉強会
Scala勉強会
 
Equality in Scala (ScalaMatsuri 2020)
Equality in Scala (ScalaMatsuri 2020)Equality in Scala (ScalaMatsuri 2020)
Equality in Scala (ScalaMatsuri 2020)
 
Javaプログラミング入門【第7回】
Javaプログラミング入門【第7回】Javaプログラミング入門【第7回】
Javaプログラミング入門【第7回】
 
Scalaz
ScalazScalaz
Scalaz
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
 
RSpecのここがすごい!
RSpecのここがすごい!RSpecのここがすごい!
RSpecのここがすごい!
 
ゆるふわScalaコップ本読書会 第7章
ゆるふわScalaコップ本読書会 第7章ゆるふわScalaコップ本読書会 第7章
ゆるふわScalaコップ本読書会 第7章
 

すごい配列楽しく学ぼう

  • 1. すごい配列楽しく学ぼう ~ Haskell の配列事情 ~ @xenophobia__    
  • 2. テーマについて 勉強会をやるらしい → 各 λ 人の好きな題材でいいらしい。 → じゃあ Haskell で何か話そう。 → でもすごい H 本出たし基本的なことはもう話題と して出尽してるよな…… → あれ?この本配列について書いてなくね? → λ < Haskell の配列も楽しく学ぼう!    
  • 3. Haskell とは!  なんてことを話している時間はない。  とりあえず今後の話に関わることとしてこれぐらい。  型に厳しい(強い静的型付けである)  キャストとかゆとりな事はしない  型が合ってないと絶対許してくれない  参照透明性が(基本的には)成り立つ  IO ・破壊的変更の扱いがめんどい特殊  unsafe ほげほげの話はしない  「型クラス」がある  「型クラス」は共通の性質を持った型の集まり  ある型クラスに関して polymorphic な関数とか書ける    
  • 4. Haskell の配列について  Haskell では、コレクションは普通リスト型で扱う。  配列はあんまり話題にならない気がする(すごい H 本にも記述は多分ない? RHW にはあった)  調べるといろいろ (Array, UArray, IArray, MArray,  IOArray, ...) でてきてよくわからない。  でも……  プロコンとかだと使いたい。  できるだけ速いほうがいい。    
  • 5. Agenda  とりあえず普通の配列( Array, UArray )  O(1) で変更できなきゃ配列じゃない! (IOArray,  IOUArray)  型クラスの話をしよう (IArray, MArray)    
  • 6. Agenda  とりあえず普通の配列( Array, UArray )  O(1) で変更できなきゃ配列じゃない! (IOArray,  IOUArray)  型クラスの話をしよう (IArray, MArray)    
  • 7. Haskell 標準の配列を使う  Array, UArray (違いはあとで。)  Array は Data.Array( または Data.Array.IArray) に ある。  UArray は Data.Array.Unboxed にある。    
  • 8. Haskell 標準の配列を使う  配列を作るには? → array 関数を使う(或いは listArray )  array (0, 3) [(0, 1), (1, 2), (2, 4), (3, 9)]  array ((1, 1), (2, 2)) [((1,1), 'a'), ((1,2), 'a'), ((2,1), 'z'),  ((2,2), 'd')]  listArray (1, 100) [0, 0 ..]  インデックスには、 Int, Char 及びそのタプルなどが 使える。  厳密には Ix 型クラスのインスタンスがすべて使える。 ここでは説明は省略。    
  • 9. Haskell 標準の配列を使う  型は?  C などと違い、インデックスもいろいろ使える。 → インデックスも型パラメタとして与える。  インデックスが Int で要素が String の Array なら、 Array Int String  となる。  インデックスが (Char, Char) で要素が Int の UArray なら、 UArray (Char, Char) Int となる。    
  • 10. Haskell 標準の配列を使う  配列 ary の要素にアクセスしたい → (!) 演算子  例) let x = ary!2 in …        let x = ary!(0, 3) in …  配列 ary の要素を更新したい → (//) 演算子  例) let ary' = ary//[(1, 2), (3, 0)] ­­ ary[1] を 2 に、 ary[3] を 0 に更新  ただし、これには後に述べるように罠が隠れている。    
  • 11. Array/UArray の違いって?  Array 型と UArray 型は、使い方はほぼ同じ。  じゃあ違いは?  Array は Box 化されている  Uarray は Box 化されていない  (´ ・ _ ・ `) ? < おまえは なにを いってるんだ    
  • 12. Array/UArray の違いって?  つまり  Array は、オブジェクトへのポインタを持った配列  UArray は、値そのものを入れる配列  もっと言うと  Array は Lazy な配列  UArray は Strict な配列    
  • 13. Array/UArray の違いって?  Array の要素を参照するときの動作  ポインタが示す先に行き、オブジェクトを返す  そのオブジェクトの値が必要になったら評価する。  もちろん、オブジェクトが評価済みならその値自体を 返す。 0 1 未評価 評価済み Eval 2 10 * 10 100 3    
  • 15. なんでそんなことになってんの?  …… ではさすがにあんまりなので。  Array が正格評価する仕様だと、例えば変数 x, y,  z を用いて ary = array (1, 3) [(1, x), (2, y), (3, z)] のようにに配列を作ると、 x, y, z は配列作成時に 全て評価されなければならない。(評価しないと 格納する値がわからない)    
  • 16. なんでそんなことになってんの?  「 x を配列に入れる」というロジックに「 x を評価す る」ことは必要か?  たとえば ary のうち一つの要素にしかアクセスしな いかもしれない。 → 「アクセスしない=使わない」ってことじゃない の?    
  • 17. なんでそんなことになってんの?  λ <使わないのに評価されるのは遅延評価とし ておかしい!( Haskell は call by need の遅延評 価!)  要素が何であるかの評価は、実際にその要素の値 が必要になるまで遅延するのがよい! てな感じなんじゃないですかね。知らんけど……    
  • 18. UArray(Unboxed Array)  Q. じゃあ UArray って何?  A. Array 遅い!って人のために。  UArray はポインタを介さない分 Array よりアクセ スが速い&場所とらない。  速さとヒープ領域を気にするならこっち使いましょ う。    
  • 19. Agenda  とりあえず普通の配列( Array, UArray )  O(1) で変更できなきゃ配列じゃない! (IOArray,  IOUArray)  型クラスの話をしよう (IArray, MArray)    
  • 20. 「 Array と参照透明性」 に関する孔明の罠  さっき (//) という「更新」演算子がでてきた。  でも、 Haskell の関数は(基本的には)参照透明性 が成り立ってなければならない。  参照透明性 : 関数と引数の組によって、返り値が 一意に決まる。    
  • 21. 「 Array と参照透明性」 に関する孔明の罠  つまり?  ary = array (1, 2) [(1, 1), (2, 2)] として、  ary!1  let ary' = ary//[(1, 2)] in ary!1  は同じ値であってほしいなければならない。    
  • 22. 「 Array と参照透明性」 に関する孔明の罠  しかし、 ary を破壊的に更新してしまった場合、 ary!1 が元の値を返すかどうかはわからない。 ary!1 が更新前に評価されれば 1 が返り、 ary!1 が更新後に評価されれば 2 が返る。 → 参照透明性に反する! ary!1 はいつ評価しても同じ値を返さなければなら ない。    
  • 23. 「 Array と参照透明性」 に関する孔明の罠  じゃあどういう実装になってんの? → 単純に、 ary には変更を加えず ary' 用の配列を新しく作る。 → これでどこをいつ参照しても矛盾は起きない。 やったね(?)    
  • 24. 「 Array と参照透明性」 に関する孔明の罠  …… なにもうまくいってません。  問題 1 :そもそも「更新」じゃなくて「新規作成」演算 子になってる  問題 2 :計算量 O(sizeof(ary)) →  プロコンでうっかり使ったりすると死ぬ  結論: (//) は更新する演算子ではなく、更新され た配列を新規作成する演算子    
  • 25. 補足  注 1 )ドキュメントにも Incremental array updates と書いてあってまぎらわしい。  注 2 ) Data.Array.IArray には、「殆どの IArray の インスタンスにおいて更新には O(N) かかる」と 書いてある。  注 3 ) Data.Array.IArray の (//) 関数の仕様自体が O(N) の計算量に本質的に関わっているわけで はない。(実際、もっと速い更新を実現する DiffArray などの IArray インスタンスもある)    
  • 26. うまい解決法はないか  破壊的更新ができれば文句ない。  Haskell で破壊的操作をうまく扱う方法として IO モナドがある。  IO モナドの文脈中ならうまいこと破壊的操作を扱 える。 → IO モナドの中でしか使えない配列を作れば万 事解決!    
  • 27. IOArray/IOUArray  Data.Array.IO にどっちも定義されている。  作成・参照・更新は全て IO アクション。 → アクションの実行順序は保証されるので、参 照と更新の順序が入れかわったりしない!    
  • 28. IOArray/IOUArray  作成: newArray(newArray_, newListArray)  newArray (lb, ub) x  で、インデックスが lb 〜 ub の x で初期化された配列を返すアクションを返す。  参照: readArray  readArray ary i で、 ary の i 番地の値を返すアクショ ンを返す。  更新: writeArray  writeArray ary i x で、 ary の i 番地の値を x に変更 するアクションを返す。    
  • 29. IOArray/IOUArray  使い方  IO モナドの中で使う。  do ary ← newArray (1, 10) 0   x ← readArray ary 1   writeArray ary 1 3   y ← readArray ary 1   ...  x, y  には 0, 3 がそれぞれ束縛される。    
  • 30. 参照透明性は?  さっきのプログラムの 2 つの readArray ary 1 って 別々の値を返してね? → readArray ary 1 はあくまで両方「 ary からイン デックス i の値を取り出す操作」を表すアクション なのであって、 x, y を返す関数ではありません。    
  • 31. Pros & Cons  正真正銘の O(1) 更新が可能!  ただ、 IO に汚染される上、インタフェースが多少め んどい。    
  • 32. 備考  IOArray 以外にも、 STArray など破壊的代入がで きる配列はある。  IO モナドと違い ST モナドは外に脱出できるの で、 IO 操作を他に使わないならこっちのほうが いいかも。  IOArray と使い勝手は一緒    
  • 33. 補足( 1 )  thaw/freeze 関数を用いて普通の配列と可変配列 との相互変換もできる。  thaw (解凍)が Immutable → Mutable の変換  freeze (凍結)が Mutable → Immutable の変換    
  • 34. 補足( 2 )  もちろん thaw も freeze も O(N) 。  ドキュメントにもちゃんと” by taking a complete copy  of it.” とある。  こういうときこそ STArray 使うといいかもしれない。  手前味噌ですが STUArray を用いたエラトステネス の篩実装例 http://d.hatena.ne.jp/g940425/20110827/1314442246  後半で unsafe な関数使ってるけど……こういう使い かたなら問題ないはず。    
  • 35. Agenda  とりあえず普通の配列( Array, UArray )  O(1) で変更できなきゃ配列じゃない! (IOArray,  IOUArray)  型クラスの話をしよう (IArray, MArray)    
  • 36. 抽象化したい!  Uarray と Array 、 IOUArray と IOArray は Box 化 / 非 Box 化の違いでしかない。 → これらの違いを無視した一般的なインタ フェースの関数を書きたい。    
  • 37. 例えば……  sumA : Int 要素を持つ Array の全要素の和    
  • 38. 例えば……  sumA をそのまま UArray に使おうとすると、当然の ように型エラーで怒られる。    
  • 39. 例えば……  型ごとに関数を用意すればお k !    
  • 40. いやいや <「お k !」じゃねえ! 関数本体全く同じじゃねえか!  こういう、形がほとんど同じ関数を連ねるのを 「ボイラープレート( boilerplate )」という → Haskeller が最も嫌うもの 私も大嫌いです  形が同じなら、まとめてかけるはず    
  • 41. IArray/MArray  変更不可配列 (Immutable Array) を抽象する型ク ラスが IArray  可変配列 (Mutable Array) を抽象する型クラスが MArray  型クラス: Iarray/MArray はそれ自体「型」ではな い( IArray  〜 型の値、は存在しない)    
  • 42. IArray/MArray  IArray a e : e 型の要素を持つ変更不可配列 a  Marray a e m : m モナドのコンテクストで変更可能 な、 e 型の要素を持つ配列 a    
  • 43. 例ふたたび  IArray を使って sumA を抽象化  GHC 拡張 FlexibleContexts が必要(理由は後述)    
  • 44. 例ふたたび  sumA :: IArray a Int => … → 「 a が Int を要素に持つ変更不可配列」 という型制約をかけている  sumA :: … => a Int Int → Int → a Int Int → Int という型を持つので、 a として当てはまる(= IArray a Int というインス タンスが宣言されている)もの全てに適用可能    
  • 45. 例ふたたび  Data.Array.IArray にインスタンスとして  IArray Array e  IArray UArray Int が宣言されている。( e は型変数で、なんでもよい) → a が Array でも UArray でも型が合う!  IArray Array Int => Array Int Int → Int OK !:インスタンス IArray Array e がある  IArray UArray Int => UArray Int Int → Int OK !:インスタンス IArray UArray Int がある    
  • 46. 補足( 3 )  Q. かける制約は IArray a e でよかったのでは?  A. 実は、 IArray UArray e という要素の型 e につい て一般化されたインスタンスはない。 (Data.Array.UArray のドキュメント参照) → なのでこの例では IArray a Int のインスタンス 宣言を使っており、そのため制約が IArray a Int となっている。  IArray Array e => Array Int Int → Int OK !:インスタンス IArray Array e がある  IArray UArray e => UArray Int Int → Int NG !:インスタンス IArray UArray e はない    
  • 47. 補足( 4 )  本来、型制約に具体的な型を入れることはできな い。 → IArray a Int という制約はふつう許されない。  これを許可するのが FlexibleContexts 拡張    
  • 48. 総括  Haskell でも普通に配列使える  しかし、速いプログラムにするには工夫が要る →使えるところでは Unboxed な配列を使う、とか  抽象化もできる → ただ、なんでもかんでも抽象化すればいいと いうわけじゃない。 Lazy/Strict が本質的な場面 もあるだろうし、競技プログラミングでわざわざ 使いもしないのに抽象化した関数を書くのは得 策でない。    
  • 49. より進んだ話題  Haskell には並列処理用行列 repa ( [hackage]http://hackage.haskell.org/packa ge/repa )という、データ並列プログラミングをサ ポートする特殊なライブラリもある。 → 配列というよりは「行列」 → ついこの間( 2012/9/24 ) GHC­7.6 にも対応  DiffArray なんてのもある( Immutable かつ更新も それなりに速い) [hackage]http://hackage.haskell.org/package/diffa rray