SlideShare a Scribd company logo
Inverse FizzBuzz を解いてみよう!
            2012/5/19

       @quassia88
自己紹介


Twitter: @quassia88

過去に、「Scalaで圏論入門」を翻訳
https://github.com/scalajp/introduction-to-category-theory-in-scala-jp/wiki
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
Inverse FizzBuzz のあらすじ
 時は2016年、関数型言語がプログラム言語界のメイ
 ンストリームとなっていた。
 すでに、FizzBuzz問題はおばあちゃんでも解けるほ
 どに陳腐化。
 Googleは採用試験に、Inverse FizzBuzzと呼ばれ
 る最新の問題を出題しようとしていた・・・



                              毒舌な
                              妹さんも
                              安心です
Inverse FizzBuzz 問題の定義



 問題:逆FizzBuzz問題

 あるリストが与えられたときに、FizzBuzzを実行する
 とそのリストを出力するような最短の連続数列を求
 めよ。
なんのこっちゃ?


要は、FizzBuzzの逆問題!
つまり、結果から原因を推定する問題。

FizzBuzz問題の復習:
非負の整数列が与えられたとき、3の倍数ならば
Fizz、5の倍数ならばBuzz、3の倍数かつ5の倍数な
らば、FizzBuzzを出力せよ。
FizzBuzzの例

 数列 { 3, 4, 5, 6 } が与えられたとする。
 この数列にFizzBuzz を適用すると、

  3 ⇒ Fizz
  4 ⇒
  5 ⇒ Buzz
  6 ⇒ Fizz

 となり、文字列の列 { Fizz,Buzz,Fizz } がえられる。
Inverse FizzBuzzの例


 では、文字列の列 { Fizz,Buzz,Fizz } が与えられた
 とする。
 この列と同じ列を出力する数列のうち、もっとも短い
 ものは何か?

 条件:
 ● 解は一意ではないが、最短のものであればどれで

 もよい
Inverse FizzBuzzの例

 先ほどのFizzBuzzの回答から、 { Fizz,Buzz,Fizz }
 を出力する数列は、 

  { 3, 4, 5, 6 }

 だと分かる。では、他の例は?

  { Fizz, Buzz } ⇒ { 3, 4, 5 } ではなく、{ 9, 10 }
  { Buzz, Fizz } ⇒ { 5, 6 }
  { Buzz, Buzz, Buzz } ⇒ 解なし!
再度 Inverse FizzBuzz の定義

 Fizz,Buzz,FizzBuzz からなる、文字列の列が与え
 られたとする。
 FizzBuzz を適用した時、この列と同じ列を出力する
 数列のうち、もっとも短いものは何か?


 条件:
 ● 解は一意ではないが、最短のものであればどれで

 もよい。
 ● 解が存在しない場合もある。何らかの対処を行う

 こと。
現在の心象

     ノ´⌒`\           ∩___∩    ━┓     /
  γ⌒´     \          | ノ\     ヽ.   ┏┛   /
 .// ""´ ⌒\ \       /  ●゛  ● |   ・    /.    ___   ━┓
 .i /  \   ,_ i )\      | ∪  ( _●_) ミ     /     / ―  \  ┏┛
  i   (・ )゛ ´( ・) i,/ \    彡、   |∪|   |    /     /  (●)  \ヽ ・
 l u   (__人_).  | .   \ /     ∩ノ ⊃  ヽ /     /   (⌒  (●) /
_\  ∩ノ ⊃ /  ━┓\  ∧∧∧∧∧∧∧/     /      ̄ヽ__) /
(  \ / _ノ |  |.  ┏┛  \<         >    /´     ___/
.\ “  /__|  |  ・     <   ━┓   >    |        \
―――――――――――――<.   ┏┛   >―――――――――――――
      ___    ━┓     <    ・     >.          ____     ━┓
    / ―\   ┏┛     <         >        / ―   \    ┏┛
  /ノ  (●)\  ・       /∨∨∨∨∨∨\      /ノ  ( ●)  \   ・
. | (●)   ⌒)\      /            \     | ( ●)   ⌒)   |
. |   (__ノ ̄  |    /    / ̄ ̄ヽ  ━┓  \   |   (__ノ ̄   /
  \        /   /    / (●) ..(● ┏┛   \  |            /
    \     _ノ  /      |   'ー=‐' i  ・      \ \_   ⊂ヽ∩\
    /´     `\/        >     く          \  /´    (,_ \.\
     |      /      _/ ,/⌒)、,ヽ_         \ |  /     \_ノ
     |     /         ヽ、_/~ヽ、__)  \        \
どうするの?


● 整数列から出力される FizzBuzz 列は当然無限
列。無限列に対して探索しろって?停止する保証
は?
● 見つからなかったら、永遠に探し続けるの?

● 解が得られたとして、それが最短の数列であるこ

とはどうやって保証する?
● それ以前に、FizzBuzz 列をどうやって数に戻すの

よ?
困った時はどうしよう?

手段その1:
力ずくで解く!
有限の数列から得られた FizzBuzz 列の部分列を
すべて列挙して、与えられた FizzBuzz 列と同じもの
がないか探す。

 → 出題者がもうやってます

手段その2:
とにかく観察してみよう
FizzBuzz 列を図示してみた
 観察すると・・・
図示すると分かること



これって循環してない?

 Fizz, Buzz, Fizz, Fizz, Buzz, Fizz, FizzBuzz

がただ繰り返しているだけ?

考えてみりゃそりゃそーだ。
倍数の出力を繰り返してるだけなんだから。
(数論、群論、数学的帰納法なんかで証明できるか
な・・・)
糸口を掴む
ある「有限の周期」で循環する列に対する探索の問
題と考えればいいのでは?

循環列なので、十分な長さの列に対して探索を行え
ば
● 有限の時間で終了できることが保証できる
● 解が得られたとして、それが最短の数列であるこ

とが保証できる
● 解が得られなかった場合は、解がないことを保証

できる
問題を分割してみる

● 循環する FizzBuzz 列を作成する
● 循環する FizzBuzz 列と、与えられた FizzBuzz

列を比較し、一致する列を列挙する
● FizzBuzz 列を数列に戻す

● 数列のなかで、最短のものを選択する



もちろん、もっとエレガントな方法もあるはず!

でも、とりあえず上に従って分割した問題を解いてみ
る
分割された問題を解いてみよう
変形 Inverse FizzBuzz 問題1


 ある非負整数 n から始まる数列があったとする。

 この数列にFizzBuzz を適用した時、最初に
 Fizz/Buzz/FizzBuzz が出力される数は何か?

 例: 
 3で始まる数列で、最初の Buzz を出力する数は?
変形 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))
 }
変形 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が得られる
変形 Inverse FizzBuzz 問題2


 ある長さのFizzBuzz列が与えられたとする。

 このFizzBuzz列 を生成した数列が n から始まるの
 が分かっている時、FizzBuzz 列を数列に直せ

 例: 
 { Fizz, FizzBuzz } を出力する12で始まる数列は?
変形 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)
 )
変形 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)
 ))
あとは自分で解いてみよう!




でも、注意事項を少々・・・
Inverse FizzBuzz の注意点
 できた!と思ったら以下のことをテストしてみよう
 ● 最短になっているか?
    { Fizz, Buzz } を与えた時に
    長さ2の列が返るか?

  解のない FizzBuzz 列を与えた時、クラッシュしな
 ●

 いか?

  空の列(Nil)を与えた時、クラッシュしないか?正
 ●

 しい結果が返るか?(「解なし」じゃないよ!)
 ● 長いFizzBuzz列に対しても、解を与えるか?
Let’s solve Inverse FizzBuzz!




  ご静聴ありがとうございました

More Related Content

Viewers also liked

代数的データ型をラムダ計算の中で表現する方法
代数的データ型をラムダ計算の中で表現する方法代数的データ型をラムダ計算の中で表現する方法
代数的データ型をラムダ計算の中で表現する方法
syamino
 
圏論とプログラミング読書会#2 資料
圏論とプログラミング読書会#2 資料圏論とプログラミング読書会#2 資料
圏論とプログラミング読書会#2 資料
53ningen
 
シャミノ計算
シャミノ計算シャミノ計算
シャミノ計算
syamino
 
圏論のおはなし
圏論のおはなし圏論のおはなし
圏論のおはなしTakeo Imai
 
OCamlの多相Variant紹介 #fpstudy
OCamlの多相Variant紹介 #fpstudyOCamlの多相Variant紹介 #fpstudy
OCamlの多相Variant紹介 #fpstudykyon mm
 
今日から始めるClojure
今日から始めるClojure今日から始めるClojure
今日から始めるClojure
Kiyotaka Kunihira
 
Material
MaterialMaterial
Material
_TUNE_
 
圏論 3分(?) クッキング
圏論 3分(?) クッキング圏論 3分(?) クッキング
圏論 3分(?) クッキング
aiya000
 
20160702_圏論の基礎
20160702_圏論の基礎20160702_圏論の基礎
20160702_圏論の基礎
matsumoring
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
Shinichi Kozake
 
C#erがF#に這い寄ってみた
C#erがF#に這い寄ってみたC#erがF#に這い寄ってみた
C#erがF#に這い寄ってみた
Hiroshi Maekawa
 
恊働ロボットCOROの開発における形式的仕様の適用事例
恊働ロボットCOROの開発における形式的仕様の適用事例恊働ロボットCOROの開発における形式的仕様の適用事例
恊働ロボットCOROの開発における形式的仕様の適用事例
Life Robotics
 
圏論とHaskellは仲良し
圏論とHaskellは仲良し圏論とHaskellは仲良し
圏論とHaskellは仲良し
ohmori
 
第一回関数型言語勉強会 大阪
第一回関数型言語勉強会 大阪第一回関数型言語勉強会 大阪
第一回関数型言語勉強会 大阪Naoki Kitora
 
圏とHaskellの型
圏とHaskellの型圏とHaskellの型
圏とHaskellの型
KinebuchiTomo
 

Viewers also liked (15)

代数的データ型をラムダ計算の中で表現する方法
代数的データ型をラムダ計算の中で表現する方法代数的データ型をラムダ計算の中で表現する方法
代数的データ型をラムダ計算の中で表現する方法
 
圏論とプログラミング読書会#2 資料
圏論とプログラミング読書会#2 資料圏論とプログラミング読書会#2 資料
圏論とプログラミング読書会#2 資料
 
シャミノ計算
シャミノ計算シャミノ計算
シャミノ計算
 
圏論のおはなし
圏論のおはなし圏論のおはなし
圏論のおはなし
 
OCamlの多相Variant紹介 #fpstudy
OCamlの多相Variant紹介 #fpstudyOCamlの多相Variant紹介 #fpstudy
OCamlの多相Variant紹介 #fpstudy
 
今日から始めるClojure
今日から始めるClojure今日から始めるClojure
今日から始めるClojure
 
Material
MaterialMaterial
Material
 
圏論 3分(?) クッキング
圏論 3分(?) クッキング圏論 3分(?) クッキング
圏論 3分(?) クッキング
 
20160702_圏論の基礎
20160702_圏論の基礎20160702_圏論の基礎
20160702_圏論の基礎
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
 
C#erがF#に這い寄ってみた
C#erがF#に這い寄ってみたC#erがF#に這い寄ってみた
C#erがF#に這い寄ってみた
 
恊働ロボットCOROの開発における形式的仕様の適用事例
恊働ロボットCOROの開発における形式的仕様の適用事例恊働ロボットCOROの開発における形式的仕様の適用事例
恊働ロボットCOROの開発における形式的仕様の適用事例
 
圏論とHaskellは仲良し
圏論とHaskellは仲良し圏論とHaskellは仲良し
圏論とHaskellは仲良し
 
第一回関数型言語勉強会 大阪
第一回関数型言語勉強会 大阪第一回関数型言語勉強会 大阪
第一回関数型言語勉強会 大阪
 
圏とHaskellの型
圏とHaskellの型圏とHaskellの型
圏とHaskellの型
 

20120519 inverse fizzbuzz を解いてみよう