Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails以外の開発一般

Haskell: ピーターからの問題を解いてみた

はじめに

👇こういう記事を見ると触発されて Haskell で解いてみたくなってしまいますね。

Ruby: Array#permutationでクイズを解いてみた

実際こういう数式系は Haskell が得意とする分野だと思います。

お題

要は下記の数式を満たす a,b,c,d,e,f,g,h,i の順列を求めろってことですね。

    \[\frac{a}{10b+c}+\frac{d}{10e+f}+\frac{g}{10h+i}=1\]

解く

数式はそのまま使えるので、まずは問題の数式をそのままラムダで書いてみます。

\[a,b,c,d,e,f,g,h,i] -> a/(10*b + c) + d/(10*e + f) + g/(10*h + i) == 1

できました。
次に、a〜iの全ての順列が欲しいです。
Haskellには Data.List というモジュールがあり、その中で permutations という配列から全ての順列を出す関数が用意されているのでこれと上記のラムダを使って解いてみます。

Prelude> -- モジュールのインポート
Prelude> :m Data.List
Prelude Data.List> filter (\[a,b,c,d,e,f,g,h,i] -> a/(10*b + c) + d/(10*e + f) + g/(10*h + i) == 1) (permutations [1..9])
[[9.0,1.0,2.0,5.0,3.0,4.0,7.0,6.0,8.0],[5.0,3.0,4.0,9.0,1.0,2.0,7.0,6.0,8.0],[7.0,6.0,8.0,5.0,3.0,4.0,9.0,1.0,2.0],[5.0,3.0,4.0,7.0,6.0,8.0,9.0,1.0,2.0],[9.0,1.0,2.0,7.0,6.0,8.0,5.0,3.0,4.0],[7.0,6.0,8.0,9.0,1.0,2.0,5.0,3.0,4.0]]

モジュールインポートを除いて、ワンライナーで解けました。
ちょっと結果の小数点が見にくいので、整数に直してみます。

Prelude Data.List> map (map round) $ filter (\[a,b,c,d,e,f,g,h,i] -> a/(10*b + c) + d/(10*e + f) + g/(10*h + i) == 1) (permutations [1..9])
[[9,1,2,5,3,4,7,6,8],[5,3,4,9,1,2,7,6,8],[7,6,8,5,3,4,9,1,2],[5,3,4,7,6,8,9,1,2],[9,1,2,7,6,8,5,3,4],[7,6,8,9,1,2,5,3,4]]

結果が見やすくなりました。
Haskell は数式を直観的に書けるので、コードもとても見やすいです(?)

以下コード

余談

Haskellには Hoogle という、型から関数を逆引きできるサービスがあります。
これは非常に便利で、少し慣れると思いあたる単語で関数を総当りで探すよりも目的の関数を見つけやすいです(体感)。
たとえば、今回使った permutations という関数は [a] -> [[a]] と検索すると上の方にヒットします。
[a] -> [[a]] を大雑把に説明すると「[a]を引数にとり[[a]]を返す。 aは多相型なのでどんな型でもよい」という感じの型を表します。

他の言語でもあったら便利そうですね。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。