プログラミングHaskell 11章切符番号選び     @dekosuke
概略 数字遊び @ twitter 切符番号選び 切符番号選びの高速化                   2
数字遊び   ランダムな4つの数字から、10を作ろう!                           3
数字遊び   Easy! => 3+2+7-2                       4
数字遊びTLを眺めてみると、問題によっては、難易度高い・・・                   5
数字遊び   累乗で解決!             6
数字遊びさらに難易度上昇           7
数字遊び   絶対値とルートで解決!?・・・                      8
数字遊び絶対値とルートで解決!?・・・                  9
数字遊び 上のTwitterの数字遊びは、使える演算が明  示されていないあいまいさがある(それ  が面白さにつながる点も) 使える演算をちゃんと決めよう!                        10
切符番号選びのルール   正数のリストが与えられる リストから好きな数だけ選んで正数を使  い、四則演算を行える 計算途中で0以下になってはいけない                       11
切符番号選びのルール[Int] -> [(Expr, Int)]整数のリストから、四則演算で作られる式とその答えのリストが作られる欲しい数は、その中に「ある」か「ない」かのどちらか                         12
切符番号選びのルールというわけで、切符番号選びのプログラムを書きましょう!                  13
切符番号選びdata Op = Add | Sub | Mul | Div--演算valid :: Op -> Int -> Int -> Boolapply :: Op -> Int -> Int -> Int--演算が正当かどうかと、演算を...
切符番号選びdata Expr = Val Int | App Op Expr Expr--式eval :: Expr -> [Int]--式の評価 (実質Maybe)--整数の組み合わせを作るため、次から色々関数を定義します--Val は適宜...
切符番号選びsubs :: [a] -> [[a]]subs [] = [[]]subs (x:xs) = yss ++ map (x:) yss         where yss = subs xs--リストの全ての部分集合を作る--集合の...
切符番号選びperms :: [a] -> [[a]]perms [] = [[]]perms (x:xs) = concat (map (interleave x)(perms xs))--集合のpermutation(並び替え)      ...
切符番号選びchoices :: [a] -> [[a]]choices xs = concat (map perms (subs xs))--全ての部分集合を含んだ順列を作る                                  ...
切符番号選びsolution :: Expr -> [Int] -> Int -> Boolsolution e ns n = elem (values e) (choices ns)&& eval e == [n]--式eを構成する数値がリス...
切符番号選び全ての解答を探す関数solutionsを作りたいsolutions :: [Int] -> Int -> [Expr]--solutions (数のリスト) 正解値-> 数のリストが生成元の式で、評価すると正解値になるもの-- so...
切符番号選びsplit :: [a] -> [([a],[a])]split [] = []split [_] = []split (x:xs) = ([x],xs):[(x:ls,rs)|(ls,rs) <- split xs]--集合を全て...
切符番号選びsplit :: [a] -> [([a],[a])]split [] = []split [_] = []split (x:xs) = ([x],xs):[(x:ls,rs)|(ls,rs) <- split xs]--集合を全て...
切符番号選びcombine :: Expr -> Expr -> [Expr]combine l r = [App o l r | o<-ops]ops :: [Op]ops = [Add,Sub,Mul,Div]--2つの式にすべての演算を適...
切符番号選びexprs :: [Int] -> [Expr]exprs [n] = [Val n]exprs ns = [e | (ls, rs) <- split ns, l<-exprs ls, r<-exprs rs, e<-combin...
完成solutions :: [Int] -> Int -> [Expr]solutions ns n = [e|ns <- choices ns, e<-exprsns, eval e==[n]]--与えられた数を生成する式をすべて探すが、遅...
高速化type Result = (Expr, Int)combine :: Result -> Result -> [Result]combine (l,x) (r,y) = [(App o l r, apply o x y)|o <-ops...
高速化results :: [Int] -> [Result]results [] = []results [n] = [(Val n, n) | n>0 ]results ns = [res | (ls,rs) <- split ns, lx...
高速化solutions :: [Int] -> Int -> [Expr]solutions ns n = [e|ns <- choices ns, (e,m)<-results ns , m==n]--式を作るうえでvalidでない演算は早...
高速化さらに工夫を…・足し算や掛け算は可換なので (Add 2 3) と (Add 3 2)は片方でいい・(Mul x 1) は自明なので除去これらの条件をvalidに入れ込む                               29
高速化・solutionsは元の数のリストに対して階乗で計算量が増大する・組合せ爆発・式の途中で計算を打ち切ると、組合せの増加速度を抑えられる→小さな工夫が指数的に効く                           30
Upcoming SlideShare
Loading in …5
×

Programming Haskell Chapter 11 切符番号選び

1,443 views
1,381 views

Published on

Programming Haskell Chapter 11 切符番号選びについて

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,443
On SlideShare
0
From Embeds
0
Number of Embeds
22
Actions
Shares
0
Downloads
5
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Programming Haskell Chapter 11 切符番号選び

  1. 1. プログラミングHaskell 11章切符番号選び @dekosuke
  2. 2. 概略 数字遊び @ twitter 切符番号選び 切符番号選びの高速化 2
  3. 3. 数字遊び ランダムな4つの数字から、10を作ろう! 3
  4. 4. 数字遊び Easy! => 3+2+7-2 4
  5. 5. 数字遊びTLを眺めてみると、問題によっては、難易度高い・・・ 5
  6. 6. 数字遊び 累乗で解決! 6
  7. 7. 数字遊びさらに難易度上昇 7
  8. 8. 数字遊び 絶対値とルートで解決!?・・・ 8
  9. 9. 数字遊び絶対値とルートで解決!?・・・ 9
  10. 10. 数字遊び 上のTwitterの数字遊びは、使える演算が明 示されていないあいまいさがある(それ が面白さにつながる点も) 使える演算をちゃんと決めよう! 10
  11. 11. 切符番号選びのルール 正数のリストが与えられる リストから好きな数だけ選んで正数を使 い、四則演算を行える 計算途中で0以下になってはいけない 11
  12. 12. 切符番号選びのルール[Int] -> [(Expr, Int)]整数のリストから、四則演算で作られる式とその答えのリストが作られる欲しい数は、その中に「ある」か「ない」かのどちらか 12
  13. 13. 切符番号選びのルールというわけで、切符番号選びのプログラムを書きましょう! 13
  14. 14. 切符番号選びdata Op = Add | Sub | Mul | Div--演算valid :: Op -> Int -> Int -> Boolapply :: Op -> Int -> Int -> Int--演算が正当かどうかと、演算を行う関数--Maybe?... 14
  15. 15. 切符番号選びdata Expr = Val Int | App Op Expr Expr--式eval :: Expr -> [Int]--式の評価 (実質Maybe)--整数の組み合わせを作るため、次から色々関数を定義します--Val は適宜省略します 15
  16. 16. 切符番号選びsubs :: [a] -> [[a]]subs [] = [[]]subs (x:xs) = yss ++ map (x:) yss where yss = subs xs--リストの全ての部分集合を作る--集合のべき乗(2^X)--subs [1, 2] = [[], [2], [1], [1,2]] 16
  17. 17. 切符番号選びperms :: [a] -> [[a]]perms [] = [[]]perms (x:xs) = concat (map (interleave x)(perms xs))--集合のpermutation(並び替え) 17
  18. 18. 切符番号選びchoices :: [a] -> [[a]]choices xs = concat (map perms (subs xs))--全ての部分集合を含んだ順列を作る 18
  19. 19. 切符番号選びsolution :: Expr -> [Int] -> Int -> Boolsolution e ns n = elem (values e) (choices ns)&& eval e == [n]--式eを構成する数値がリストnsに含まれている かつ 式eを評価すると値nになる 19
  20. 20. 切符番号選び全ての解答を探す関数solutionsを作りたいsolutions :: [Int] -> Int -> [Expr]--solutions (数のリスト) 正解値-> 数のリストが生成元の式で、評価すると正解値になるもの-- solutions [1,2,3] 3 = [Val 3, Add 1 2, Add 2 1] 20
  21. 21. 切符番号選びsplit :: [a] -> [([a],[a])]split [] = []split [_] = []split (x:xs) = ([x],xs):[(x:ls,rs)|(ls,rs) <- split xs]--集合を全ての場所で2つに割る-- split [1,2,3,4] = [([1],[2,3,4]), ([1,2],[3,4]),([1,2,3],[4])] 21
  22. 22. 切符番号選びsplit :: [a] -> [([a],[a])]split [] = []split [_] = []split (x:xs) = ([x],xs):[(x:ls,rs)|(ls,rs) <- split xs]--集合を全ての場所で2つに割る-- split [1,2,3,4] = [([1],[2,3,4]), ([1,2],[3,4]),([1,2,3],[4])] 22
  23. 23. 切符番号選びcombine :: Expr -> Expr -> [Expr]combine l r = [App o l r | o<-ops]ops :: [Op]ops = [Add,Sub,Mul,Div]--2つの式にすべての演算を適用--[Add 式1 式2, Sub 式1 式2, Mul 式1 式2, Div式1 式2] 23
  24. 24. 切符番号選びexprs :: [Int] -> [Expr]exprs [n] = [Val n]exprs ns = [e | (ls, rs) <- split ns, l<-exprs ls, r<-exprs rs, e<-combine l r]--数値のリストを全て一回ずつ使った式すべてを返す (本当はこれは遅い(後述) ) 24
  25. 25. 完成solutions :: [Int] -> Int -> [Expr]solutions ns n = [e|ns <- choices ns, e<-exprsns, eval e==[n]]--与えられた数を生成する式をすべて探すが、遅い… (4分 @ モダンなマシン)(Sub 1 2) <- こういう式が途中に出たら打ち切りたい 25
  26. 26. 高速化type Result = (Expr, Int)combine :: Result -> Result -> [Result]combine (l,x) (r,y) = [(App o l r, apply o x y)|o <-ops, valid o x y]--2つのExprに対して、validな演算すべてを適用 26
  27. 27. 高速化results :: [Int] -> [Result]results [] = []results [n] = [(Val n, n) | n>0 ]results ns = [res | (ls,rs) <- split ns, lx<-results ls,ry <-results rs, res<-combine lx ry]--数値のリストを、すべて使った式を作って評価する-- [1,2] -> [(Add 1 2, 3), (Mul 1 2, 2)] 27
  28. 28. 高速化solutions :: [Int] -> Int -> [Expr]solutions ns n = [e|ns <- choices ns, (e,m)<-results ns , m==n]--式を作るうえでvalidでない演算は早めに打ち切る--10数秒 @ モダンなマシン 28
  29. 29. 高速化さらに工夫を…・足し算や掛け算は可換なので (Add 2 3) と (Add 3 2)は片方でいい・(Mul x 1) は自明なので除去これらの条件をvalidに入れ込む 29
  30. 30. 高速化・solutionsは元の数のリストに対して階乗で計算量が増大する・組合せ爆発・式の途中で計算を打ち切ると、組合せの増加速度を抑えられる→小さな工夫が指数的に効く 30

×