20120519 inverse fizzbuzz を解いてみよう

4,698 views

Published on

2012年5月19日に開催された、「第一回関数型言語勉強会 大阪」での発表資料です。

コードとか:
https://github.com/quassia88/InverseFizzBuzz/

まとめとか:
http://togetter.com/li/306278

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
4,698
On SlideShare
0
From Embeds
0
Number of Embeds
2,897
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

20120519 inverse fizzbuzz を解いてみよう

  1. 1. Inverse FizzBuzz を解いてみよう! 2012/5/19 @quassia88
  2. 2. 自己紹介Twitter: @quassia88過去に、「Scalaで圏論入門」を翻訳https://github.com/scalajp/introduction-to-category-theory-in-scala-jp/wiki
  3. 3. Inverse FizzBuzz って何? Krishnan Raman氏のブログ 「just another scala quant」 に5月3日付でアップロード。翌々週あたりから拡散。 原文 http://www.jasq.org/2/post/2012/05/inverse-fizzbuzz.html 日本語訳 http://d.hatena.ne.jp/matarillo/20120515/p1 コードゴルフ http://golf.shinh.org/p.rb?Invert+FizzBuzz
  4. 4. Inverse FizzBuzz のあらすじ 時は2016年、関数型言語がプログラム言語界のメイ ンストリームとなっていた。 すでに、FizzBuzz問題はおばあちゃんでも解けるほ どに陳腐化。 Googleは採用試験に、Inverse FizzBuzzと呼ばれ る最新の問題を出題しようとしていた・・・ 毒舌な 妹さんも 安心です
  5. 5. Inverse FizzBuzz 問題の定義 問題:逆FizzBuzz問題 あるリストが与えられたときに、FizzBuzzを実行する とそのリストを出力するような最短の連続数列を求 めよ。
  6. 6. なんのこっちゃ?要は、FizzBuzzの逆問題!つまり、結果から原因を推定する問題。FizzBuzz問題の復習:非負の整数列が与えられたとき、3の倍数ならばFizz、5の倍数ならばBuzz、3の倍数かつ5の倍数ならば、FizzBuzzを出力せよ。
  7. 7. FizzBuzzの例 数列 { 3, 4, 5, 6 } が与えられたとする。 この数列にFizzBuzz を適用すると、 3 ⇒ Fizz 4 ⇒ 5 ⇒ Buzz 6 ⇒ Fizz となり、文字列の列 { Fizz,Buzz,Fizz } がえられる。
  8. 8. Inverse FizzBuzzの例 では、文字列の列 { Fizz,Buzz,Fizz } が与えられた とする。 この列と同じ列を出力する数列のうち、もっとも短い ものは何か? 条件: ● 解は一意ではないが、最短のものであればどれで もよい
  9. 9. Inverse FizzBuzzの例 先ほどのFizzBuzzの回答から、 { Fizz,Buzz,Fizz } を出力する数列は、  { 3, 4, 5, 6 } だと分かる。では、他の例は? { Fizz, Buzz } ⇒ { 3, 4, 5 } ではなく、{ 9, 10 } { Buzz, Fizz } ⇒ { 5, 6 } { Buzz, Buzz, Buzz } ⇒ 解なし!
  10. 10. 再度 Inverse FizzBuzz の定義 Fizz,Buzz,FizzBuzz からなる、文字列の列が与え られたとする。 FizzBuzz を適用した時、この列と同じ列を出力する 数列のうち、もっとも短いものは何か? 条件: ● 解は一意ではないが、最短のものであればどれで もよい。 ● 解が存在しない場合もある。何らかの対処を行う こと。
  11. 11. 現在の心象     ノ´⌒`\           ∩___∩    ━┓     /  γ⌒´     \          | ノ\     ヽ.   ┏┛   / .// ""´ ⌒\ \       /  ●゛  ● |   ・    /.    ___   ━┓ .i /  \   ,_ i )\      | ∪  ( _●_) ミ     /     / ―  \  ┏┛  i   (・ )゛ ´( ・) i,/ \    彡、   |∪|   |    /     /  (●)  \ヽ ・ l u   (__人_).  | .   \ /     ∩ノ ⊃  ヽ /     /   (⌒  (●) /_\  ∩ノ ⊃ /  ━┓\  ∧∧∧∧∧∧∧/     /      ̄ヽ__) /(  \ / _ノ |  |.  ┏┛  \<         >    /´     ___/.\ “  /__|  |  ・     <   ━┓   >    |        \―――――――――――――<.   ┏┛   >―――――――――――――      ___    ━┓     <    ・     >.          ____     ━┓    / ―\   ┏┛     <         >        / ―   \    ┏┛  /ノ  (●)\  ・       /∨∨∨∨∨∨\      /ノ  ( ●)  \   ・. | (●)   ⌒)\      /            \     | ( ●)   ⌒)   |. |   (__ノ ̄  |    /    / ̄ ̄ヽ  ━┓  \   |   (__ノ ̄   /  \        /   /    / (●) ..(● ┏┛   \  |            /    \     _ノ  /      |   ー=‐ i  ・      \ \_   ⊂ヽ∩\    /´     `\/        >     く          \  /´    (,_ \.\     |      /      _/ ,/⌒)、,ヽ_         \ |  /     \_ノ     |     /         ヽ、_/~ヽ、__)  \        \
  12. 12. どうするの?● 整数列から出力される FizzBuzz 列は当然無限列。無限列に対して探索しろって?停止する保証は?● 見つからなかったら、永遠に探し続けるの?● 解が得られたとして、それが最短の数列であることはどうやって保証する?● それ以前に、FizzBuzz 列をどうやって数に戻すのよ?
  13. 13. 困った時はどうしよう?手段その1:力ずくで解く!有限の数列から得られた FizzBuzz 列の部分列をすべて列挙して、与えられた FizzBuzz 列と同じものがないか探す。 → 出題者がもうやってます手段その2:とにかく観察してみよう
  14. 14. FizzBuzz 列を図示してみた 観察すると・・・
  15. 15. 図示すると分かることこれって循環してない? Fizz, Buzz, Fizz, Fizz, Buzz, Fizz, FizzBuzzがただ繰り返しているだけ?考えてみりゃそりゃそーだ。倍数の出力を繰り返してるだけなんだから。(数論、群論、数学的帰納法なんかで証明できるかな・・・)
  16. 16. 糸口を掴むある「有限の周期」で循環する列に対する探索の問題と考えればいいのでは?循環列なので、十分な長さの列に対して探索を行えば● 有限の時間で終了できることが保証できる● 解が得られたとして、それが最短の数列であることが保証できる● 解が得られなかった場合は、解がないことを保証できる
  17. 17. 問題を分割してみる● 循環する FizzBuzz 列を作成する● 循環する FizzBuzz 列と、与えられた FizzBuzz列を比較し、一致する列を列挙する● FizzBuzz 列を数列に戻す● 数列のなかで、最短のものを選択するもちろん、もっとエレガントな方法もあるはず!でも、とりあえず上に従って分割した問題を解いてみる
  18. 18. 分割された問題を解いてみよう
  19. 19. 変形 Inverse FizzBuzz 問題1 ある非負整数 n から始まる数列があったとする。 この数列にFizzBuzz を適用した時、最初に Fizz/Buzz/FizzBuzz が出力される数は何か? 例:  3で始まる数列で、最初の Buzz を出力する数は?
  20. 20. 変形 Inverse FizzBuzz 問題1回答例 /** * satisfies を満たす start から最も近い数を返す * start が satisfies を満たさなかった場合、 * next によって次の数が与えられる */ def nearestNumber( satisfies:Int => Boolean, next:Int => Int, start:Int):Int = {   if(satisfies(start)) start   else nearestNumber(satisfies,next,next(start)) }
  21. 21. 変形 Inverse FizzBuzz 問題1回答例 /** * FizzBuzz の逆写像を返す */ def inverseMapOfFB(str:String):Int => Int = str match { case "fizz" => nearestNumber(x=> x%3==0 && x%5!=0 && x >= 3, _+1, _) case "buzz" => nearestNumber(x=> x%5==0 && x%3!=0 && x >= 5, _+1, _) case "fizzbuzz" => nearestNumber(x=> x%15==0 && x >= 15, _+1, _) } inverseMapOfFB("buzz")(3) // 5が得られる
  22. 22. 変形 Inverse FizzBuzz 問題2 ある長さのFizzBuzz列が与えられたとする。 このFizzBuzz列 を生成した数列が n から始まるの が分かっている時、FizzBuzz 列を数列に直せ 例:  { Fizz, FizzBuzz } を出力する12で始まる数列は?
  23. 23. 変形 Inverse FizzBuzz 問題2回答例 /** * 関数列 funcs に start を順に適用した数列を返す */ def chainSeq( start:Int, funcs:List[Int=>Int]):List[Int] = funcs match { case Nil => Nil case _ => funcs.head(start) :: chainSeq(funcs.head(start) +1,funcs.tail) } chainSeq( 12, List("fizz","fizzbuzz").map(inverseMapOfFB) )
  24. 24. 変形 Inverse FizzBuzz 問題2回答例 /** * 連続数列を返す */ def contiguousSeq(xs:List[Int]):List[Int]=xs match { case Nil => Nil case x => (x.head to x.last).toList } contiguousSeq(chainSeq( 12, List("fizz","fizzbuzz").map(inverseMapOfFB) ))
  25. 25. あとは自分で解いてみよう!でも、注意事項を少々・・・
  26. 26. Inverse FizzBuzz の注意点 できた!と思ったら以下のことをテストしてみよう ● 最短になっているか? { Fizz, Buzz } を与えた時に 長さ2の列が返るか?  解のない FizzBuzz 列を与えた時、クラッシュしな ● いか?  空の列(Nil)を与えた時、クラッシュしないか?正 ● しい結果が返るか?(「解なし」じゃないよ!) ● 長いFizzBuzz列に対しても、解を与えるか?
  27. 27. Let’s solve Inverse FizzBuzz!  ご静聴ありがとうございました

×