技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

Scala 関数型デザイン&プログラミング:Exercize2.1

真面目にやろうかと思った。

書籍はこれ

まずは指定 N 番目のフィボナッチ数計算関数を tail call recursive (末尾再帰)な関数で実装しろとのこと。
まず単純にフィボナッチ数列の実装をしてみる。

Wikipedia 先生 にお越しいただこう。

フィボナッチ数 - Wikipedia

object Exercise2_1 extends App {

  def fib(n: Long): Long = n match {
    case 0 => 0
    case 1 => 1
    case _ => fib(n - 2) + fib(n - 1)
  }

  for (i <- (0 to 10)) {
    println(s"$i : ${fib(i)}")
  }
}

これが末尾再帰かを判定するには、Scala の「scala.annotation.tailrec」を使えばいい。

  import scala.annotation.tailrec

  @tailrec
  def fib(n: Long): Long = n match {
    case 0 => 0
    case 1 => 1
    case _ => fib(n - 2) + fib(n - 1)
  }

  for (i <- (0 to 10)) {
    println(s"$i : ${fib(i)}")
  }

コンパイルすると、下記のエラーだ

[info] Compiling 1 Scala source to /Users/xxxx/Documents/projects/scala-function/part1/target/scala-2.11/classes...
[error] /Users/xxxx/Documents/projects/scala-function/part1/src/main/scala/Excercise2_1.scala:24: could not optimize @tailrec annotated method fib: it contains a recursive call not in tail position
[error]     case _ => fib(n - 2) + fib(n - 1)

it contains a recursive call not in tail position 最後の処理(return 前の最後の処理)で再起してないと言われた。

こう読み替えるとわかりやすいが、再起した結果に何らかの処理を加えてはならないということだ。

で、1時間位悩んだわけなのだが、結論から行こう。

考え方を改めないといけないのだ。n は「n 番目の計算結果を得る」という考え方をするのではなくて、「後 n 回計算する」と考える。
その上で、引数を考えると、下記で計算できるのではないだろうか?

後 5 回計算すると考えた時、

  1. 残 5 回、初期値 0
  2. 残 4 回、初期値 1 こう考えれば初期2回は特別なんだと考えて良さそうだ。
  3. 残 3 回、2 回目の値 + 1回目の値
  4. 残 2 回、3 回目の値 + 2回目の値 = (2 回目の値 + 1回目の値) + 2回目の値
  5. 残 1 回、4 回目の値 + 3回目の値 = ((2 回目の値 + 1回目の値) + 2回目の値) + (2 回目の値 + 1回目の値)

これを一般化して考えると、

  • 残り 1 回 = 前回 + 前々回
  • 残り 2 以上 = カウント減算、前回 + 前々回、前回

これを愚直に再起に書くとこうなる。普通に tailrec でコンパイル可能だ。

    @tailrec
    def fib(n: Long, n1: Long, n2: Long): Long = {
      n match {
        case 1 => n1 + n2
        case _ => sub(n - 1, n1 + n2, n1)
      }
    }

しかし、計算回数 0 回目、1回目という特殊ケースもあるので、事前にその答えを設定する。

  def fib(n: Long): Long = {

    @tailrec
    def sub(n: Long, n1: Long, n2: Long): Long = {
      n match {
        case 1 => n1 + n2
        case _ => sub(n - 1, n1 + n2, n1)
      }
    }

    n match {
      case 0 => 0
      case 1 => 1
      case _ => sub(n - 1, 1, 0)
    }
  }

こうなるはず。

試してみようか

  for (i <- (1 to 20)) {
    println(s"$i : ${fib(i)}")
  }

実行

$ sbt run
[info] Loading global plugins from /Users/xxxx/.sbt/0.13/plugins
[info] Set current project to sample (in build file:/Users/azalea/Documents/projects/scala-function/part1/)
[info] Compiling 1 Scala source to /Users/xxxx/Documents/projects/scala-function/part1/target/scala-2.11/classes...
[info] Running Excercise2_1 
1 : 1
2 : 1
3 : 2
4 : 3
5 : 5
6 : 8
7 : 13
8 : 21
9 : 34
10 : 55
11 : 89
12 : 144
13 : 233
14 : 377
15 : 610
16 : 987
17 : 1597
18 : 2584
19 : 4181
20 : 6765

正しそうだ

投票が近づいて来たので、40代以下に言っておこうか

なんで皆の税率が上がって、将来の年金まで気にするようになるのか、その理由をざっくり説明する。

なんで老人向けの介護とか福祉がこの時期叫ばれるのか?

まず、この時期になると声高に叫ばれることがある。それは高齢者福祉だ。
最近では少子化対策で児童福祉というパターンも多い。
そんな中気にして欲しいのは、「働く世代である 20-40 に対する内容が声高に叫ばれないのは何故か?」だ。

結論から言おう。

その世代は投票しないから色々言っても無駄だとどの政党も諦めてるからだ

公益財団法人、明るい選挙推進協会 のデータを見ればわかる。

もっとも投票しているのは 60 代を筆頭に、50,70,40 代と続いている(平成26年度)。
つまり政治家は、この年代にアピールした方が当選しやすいって寸法だ。

邪推かもしれないが、少子化対策云々を声高にする背景すら、50 代が 2 位という数字を見れば、「そろそろ引退するし、今後養ってくれる世代を増やしたい」と思っている世代の投票を拾いたいという意図が見え隠れしてるとも言えないだろうか?

そうは言ってもこれまでやってこれたんじゃない?

そういう人は多そうだ。

だが、英国の離脱を機に、続々離脱しようかという声が上がり始め、EU 自体崩壊し始めてる。
要するに目に見える世界経済の混乱が迫ってるんだ。

さぁこれで働く世代だけ割を食う構造で、不幸にならないと言い切れるのか?

ここで怖い話を教えておこう。

そんな状況を生み出した英国の EU 離脱なのだが、その原因は ご老人達 だという事実を。

6/25 日の 日本経済新聞 の記事を抜粋しよう。

欧州連合(EU)離脱の是非を問いかけた23日の英国民投票では、英国人の世代間の意識の違いが浮き彫りになった。52%対48%と僅差で離脱派が勝利したが、投票先を年代別にみた各種調査では、年齢が高くなるほど離脱を支持し、逆に30代以下の若年層は残留が多かった。

ニュースサイトが消えた場合も考えて、失礼かもしれないがグラフも転載させてもらう。

f:id:white-azalea:20160702003100j:plain

そう、離脱を望んだのは紛れもなくご老人達だ。

ではご老人達はなぜ離脱に傾いたのだろうか?それは英国ご当地新聞の BBC に聞いてみる。

  • 離脱すれば経済打撃があるという残留派、離脱の影響を悪しざまに言うのは、私利私欲から英国を批判する無責任な金持ちエリートだと一蹴する離脱派確執があった
  • EU 離脱で浮いた金をNHS(国民医療サービス)に3億5000万ポンド突っ込むと公約があった
  • 移民が増えたら混乱するけど、拒否するなら EU の協調ルールは邪魔

なんてのがある。
残留派が若い世代というのは、自由移動と経済域が広ければ、その分雇用があるからだ。

しかし既に引退したご老人に雇用なんざ知った事ではない。そんな事より老後衰えた体に福祉を欲しがったんだ。

それを引き起こしたのは投票を軽く見た若い世代の責任もある

政治に興味がないと放置した挙句、楽観視してたら後になって慌てたわけだ。

www.itmedia.co.jp

そして投票のやり直しを求めた

http://news.tbs.co.jp/newseye/tbs_newseye2806734.htmlnews.tbs.co.jp

しかしそれは叶わない。

www.sankei.com

覆水盆に返らずとはこのことだ。

ご老人の方が投票率が高い日本でも同じ事は起こり得る

どうだろう?日本は周囲に気を使うとも言われているが、 こんな記事 だってある。

「騒がしい」など従来の静かな環境を維持したい高齢者らの苦情を受けて開園を延期したり、「平穏な日常生活が侵害された」として、開園後に訴訟に発展したりするケースもある。

誰もが好々爺なんていいもんじゃない(もちろん居ないとは言わないが)。
彼らも一人の人だ。散々働いた後の老後なんだし好きにしたいという気持ちだってあるだろう。

悪いがこんな記事を書いている自分だって、投票先は自分の利害で決める。

止める手はあるのか?

はっきり言えば今すぐの改善はできない。

しかし、動かなければ永久に改善できない問題でもある。

どうするか?
わかりきった事だ。

「白紙でも良いから若い世代が投票すれば良い」

今からマニフェスト読み直して吟味して…なんてのは正直難しいだろう。
だから今すぐそんな事をするくらいなら白紙で良いんだ。

少なくとも若い世代は投票する意思があるという事を示すんだ。

若い世代が白紙(支持政党はない)と投票した事になる。
そうすればその票は要するに浮動票なんだ。
票集めが必要な政治家はその票を無駄にはしたくない。

「この世代は取り込む価値がある」

と思わせる事が出来れば良いのだ。
そうすれば、働く世代に有利な条件を提示してくるようになる。

当然ながらその後も継続しないと「なんだ一過性かよ」と見放されること請け合いなのだが…

投票所まで歩って何分だろう?移動は面倒かも知れないが、建物の中に入って白紙でも出して出てくるなんてものの十分の話だ。

「自分一人がやったって変わらないでしょう?」そういうから阿呆なのだ。

有権者は無数にいるんだが、さっきの話を思い出そう。

黙ってれば老人共の為だけに君らの生活が犠牲になっていくという事実を。

みんな言ってる事だけど、投票にも参加しない奴に、政治や税金の愚痴を言う資格なんざない。

愚痴を言う位なら数年に1回の数時間位、白紙投票でもして「俺はお前らを支持しない!」と声高に言ってみてはどうだろう?

一応

煽るような事ばかり書いてすまないとは思う。

しかし 現実問題 なんだ。

僕もそうだが、これからも日本で生きるなら避け続けるほど事態は悪化する。
そんな危機感を持ってるのは僕だけではないはずだ。

願わくば、少しでも気にしてくれる若者の目に留まる事を祈ろう。

WindowsでYeaomanしてみる

表題の通り。
環境は Winows10 …つってもあんま意味ないな。

まずは Node.js から。

といっても Windowsインストーラあるから楽勝だね。
v4.2.6 をインストール。面倒なので PATH もひいてもらう。

C:\test>node -v
v4.2.6

次、Git for Windows
バージョンに特にこだわりはない。

ダウンロードであったのが 2.7.1 なので、それをそのまま使う。

GUI?いらんでしょ。Consoleで動くようにだけしておく。
改行コードは lf だよね。

C:\test>git --version
git version 2.7.1.windows.1

さて

Yeoman, Bower, Grunt 突っ込む

コマンドで

npm install yo bower grunt-cli -g

すると

―――中略
Yeoman Doctor
Running sanity checks on your system

√ Global configuration file is valid
√ NODE_PATH matches the npm root
√ Node.js version
√ No .bowerrc file in home directory
√ No .yo-rc.json file in home directory
× npm version

Your npm version is outdated.

Upgrade to the latest version by running:
npm install -g npm

ゴフゥ…。黙って npm install -g npm して再度インストールをかけて成功。

Let's Yo

シンプルに Bootstrap-Coffee-Less のパッケージでも落とすか。

このへん「Generators | Yeoman」から検索して、こんなものを発見

GitHub - websiddu/generator-bs-less-coffee-webfont: A yeoman generator with boostrap, less, coffee, web fonts(autogenerated font icons) and gh-pages deployment

手始めにこれでいいかなと。

D:\sources>mkdir web_templates

D:\sources>cd web_templates

D:\sources\web_templates>mkdir example_yeaoman

D:\sources\web_templates>cd example_yeaoman

D:\sources\web_templates\example_yeaoman> npm install -g generator-bs-less-coffee-webfont

中略

| | +-- run-async@0.1.0
| | +-- shelljs@0.3.0
| | +-- text-table@0.2.0
| | `-- underscore.string@2.4.0
| `-- yosay@1.1.0
|   +-- ansi-regex@2.0.0
|   +-- pad-component@0.0.1
|   +-- repeating@2.0.0
|   | `-- is-finite@1.0.1
|   +-- string-width@1.0.1
|   | +-- code-point-at@1.0.0
|   | | `-- number-is-nan@1.0.0
|   | `-- is-fullwidth-code-point@1.0.0
|   +-- taketalk@1.0.0
|   | `-- get-stdin@4.0.1
|   `-- word-wrap@1.1.0
`-- UNMET PEER DEPENDENCY generator-karma@>=0.9.0

npm WARN generator-bs-less-coffee-webfont@0.0.6 requires a peer of generator-karma@>=0.9.0 but none was installed.

D:\sources\web_templates\example_yeaoman>

さっくりできたっぽい。

後はなにも考えず

D:\sources\web_templates\example_yeaoman>yo bs-less-coffee-webfont

     _-----_
    |       |    .--------------------------.
    |--(o)--|    |  Superpower is with you  |
   `---------´   | when Yeoman is with you! |
    ( _´U`_ )    '--------------------------'
    /___A___\
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `

? What more would you like?
>(*) Bootstrap Javascript files
 ( ) respond.js (mediaquery polyfill for ie6-8)

素敵なおっさんの問いかけに答える。

? What more would you like? Bootstrap Javascript files
? Do you want to deploy your project to Github Pages? This requires an empty Gi
thub repository. No
   create Gruntfile.js
   create package.json
   create .gitignore
   create .gitattributes
   create .bowerrc
   create bower.json
   create .jshintrc
   create .editorconfig
   create app\favicon.ico
   create app\404.html
   create app\robots.txt
   create app\.htaccess
   create app\styles\main.less
   create app\styles\pages\index.less
   create app\styles\utils\icons.less
   create app\index.html
   create app\scripts\hello.coffee
   create app\scripts\main.js
Error bs-less-coffee-webfont

You don't seem to have a generator with the name mocha installed.
You can see available generators with npm search yeoman-generator and then install them with npm install [name].
To see the 1 registered generators run yo with the `--help` option.

D:\sources\web_templates\example_yeaoman>

とテンプレが出来上がる。

npm と bower の読み込み

node_modules はデフォルト空。
これは、package.json に書いてある、依存モジュールをインストールすれば埋まる。

D:\sources\web_templates\example_yeaoman>npm install
npm WARN deprecated lodash@0.9.2: lodash@<3.0.0 is no longer maintained. Upgrade to lodash@^4.0.0
npm WARN deprecated lodash@2.4.2: lodash@<3.0.0 is no longer maintained. Upgrade to lodash@^4.0.0
loadDep:pause -> fetch    \ |#################--------
----中略
    +-- parse-ms@1.0.0
    `-- plur@1.0.0

npm WARN example-yeaoman@0.0.0 No description
npm WARN example-yeaoman@0.0.0 No repository field.
npm WARN example-yeaoman@0.0.0 No license field.

D:\sources\web_templates\example_yeaoman>

途中 Python ねえよとか見た気がしないではないが、先に進む。
名前の通り構成なら Python 何に使うんだろうか…。

まぁ Bower も入れる。

D:\sources\web_templates\example_yeaoman>bower install
bower not-cached    git://github.com/twbs/bootstrap.git#>=3.0.0
bower resolve       git://github.com/twbs/bootstrap.git#>=3.0.0
bower not-cached    git://github.com/Modernizr/Modernizr.git#>=2.6.2
bower resolve       git://github.com/Modernizr/Modernizr.git#>=2.6.2
bower not-cached    git:
--- 中略
jquery#2.2.0 app\bower_components\jquery

modernizr#3.3.1 app\bower_components\modernizr

bootstrap#3.3.6 app\bower_components\bootstrap
└── jquery#2.2.0

D:\sources\web_templates\example_yeaoman>

ほう、IE9 以下お断りですかw

まぁ grunt serve

D:\sources\web_templates\example_yeaoman>  grunt serve
Running "serve" task
Warning: Task "coffee" not found. Use --force to continue.

Aborted due to warnings.


Execution Time (2016-02-08 13:01:47 UTC)
loading tasks  24ms  ████████████████████████████████████ 75%
serve           7ms  ███████████ 22%
Total 32ms

What's !?

coffee なんてタスクねーよと怒られてる。
gruntfile 覗くと、

// 中略
    coffee: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/scripts',
          src: '{,*/}*.coffee',
          dest: '<%= yeoman.app %>/scripts',
          ext: '.js'
        }]
      }
    },

書かれてるね。で、どこでモジュールロードしてるのかなと思ったら、先頭近くに

  // load all grunt tasks
  require('load-grunt-tasks')(grunt);

これっぽいな。
node_modules の中漁って、index.js 読むと

'use strict';
var path = require('path');
var pkgUp = require('pkg-up');
var multimatch = require('multimatch');
var arrify = require('arrify');
var resolvePkg = require('resolve-pkg');

module.exports = function (grunt, opts) {
    opts = opts || {};

    var pattern = arrify(opts.pattern || ['grunt-*', '@*/grunt-*']);
    var config = opts.config || pkgUp.sync();

// 以下略

node_modules 内から、grunt- で始まるタスクを全部読み込む仕様のようで、改めて探してみると「grunt-contlib-coffee」が無い。
お前が犯人か。

D:\sources\web_templates\example_yeaoman>npm install grunt-contrib-coffee --save-dev

で grunt serve っと

f:id:white-azalea:20160208221451p:plain

ファイル編集するたびに勝手にコンパイルしてくれるのは実に楽。

Scala で解く「プログラマ脳を鍛える数学パズル」

病院行ったついでに待ち時間暇すぎて書店で見かけたやつ。

www.amazon.co.jp

これの問2 1000 - 9999 の中で、「351 , 3 * 51 = 153」(計算結果が元の逆順になる)みたいな数字を見つけ出せ。
使っていいのは四則演算のみで、必ず1回は計算すること。

これ、JavaScript/Ruby/Python だと瞬殺できる。
こいつらには eval があるので、四則演算「+-*/(何もなし)」を適当に埋め込んで eval すればいい。

しかしコンパイル言語でそんなファジーな事は残念ながらできない。
なので、真面目に考えた。

基本的に +-/ を入れた時点で、4桁の結果を出すことが不可能である(厳密には可能だが、組み合わせが存在しない)事を考えると、どこに掛け算の演算子を入れるかの世界になってくる。

演算子を入れれるパターンは、4桁という点で下記 7 パターンしか存在しない。

X XXX (1, 3)
XX XX (2, 2)
XXX X (3, 1)
X X XX (1, 1, 2)
X XX X (1, 2, 1)
XX X X (2, 1, 1)
X X X X (1, 1, 1, 1)

の7通りのみ。

っつー事で、substring で分解して、掛け算走らせればOK

object Main extends App {
  val splitPatterns = Seq(
    Seq(1, 3), Seq(2, 2), Seq(3, 1), 
    Seq(1, 1, 2), Seq(1, 2, 1), Seq(2, 1, 1), 
    Seq(1, 1, 1, 1)
  )

  def split(s: String, p: Seq[Int]): Seq[String] =
    s.substring(0, p.head) +: (if (p.tail.isEmpty) Seq.empty else split(s.substring(p.head), p.tail))

  (1000 to 9999).foreach(v => {
    splitPatterns.foreach(p => {
      val origin = v.toString
      val seq = split(origin, p).map(_.toInt)
      if(seq.product == origin.reverse.toInt) {
        println(s"Found Answer: $v ($seq)")
      }
    })
  })
}

結果

[info] Running Main 
Found Answer: 5931 (List(5, 9, 31))
[success] Total time: 4 s, completed 2016/01/17 19:10:21

最初に掛け算以外考えなくて済むというところに気づくと、上記みたいな解になるが、後から四足演算を計算しようと考えた時に、下記みたいな配列作って、計算で再起すべきかとか考えてしまった…。
何かスッキリ実装できる方法がないのかと思わなくはない。

  val operatorFunc: Seq[Function2[Int, Int, Int]] = Seq(
    (a, b) => a * b, (a, b) => a - b, (a, b) => a / b
  )

split を tail call にするのもまだ慣れていないせいかなかなか上手く行ってない…。
別に深くなるわけでもないので、気にしなかったのだが。

というか、他の言語は「逆ポーランド記法使う」ってそれむしろどうやるのかわからなかった…。

JavaScript(CoffeeScript) で似非 Ctrl + F 作ってみた。

まじかと思ったんだけど、マジだったので驚いてる。

shertan.me

ちょっと待て基本だろ常考
こんなもん、Windows XP 初期の時代からデフォルトだぜ?

Keyboard Shortcuts for Internet Explorer 6

記憶が確かなら、Windows 98 時代からあった気もする。

まぁ、言ってもしょうがない。
仕方ないので、それっぽいものを作ってみた。

github.com

f:id:white-azalea:20151025153314p:plain

いつも通り、Play2.4 なので、Java8 入ってれば動くはず。

続きを読む

Play2.4 でネストしたJsonをバインドする

何で今更かというと、これつかえねーかなと思ったから。

最初は、Forms でのバインドをしようとしたのだけど、早速フォーラムが見つかりました。
キーワードは Play recursive form

https://groups.google.com/forum/#!topic/play-framework/Ya1hPmR2QtY

この中で、「Form はそもそもHttpRequestを前提にしてんだからそんな事すんじゃねぇ」と言われていて、「Play Json 使え」とも誰か言ってた。
そこで、キーワード変更で、「Play recursive json」でググったところ、

ScalaJsonCombinators

を発見。

2.4 になってかなり使いやすくなってきてたので、これでざっくり実装してみた。

import play.api.libs.json._ // JSON library
import play.api.libs.json.Reads._ // Custom validation helpers
import play.api.libs.functional.syntax._ // Combinator syntax


case class Nested(name: String, content:String, friends: Seq[Nested])

implicit lazy val userReads: Reads[Nested] = (
  (__ \ "name").read[String] and
  (__ \ "content").read[String] and
  (__ \ "friends").lazyRead(Reads.seq[Nested](userReads))
)(Nested)

val json = Json.parse("""{"name":"Example", "content":"content", "friends":[{"name":"ChildName", "content":"childContent", "friends":[]}]}""")
val result = json.validate[Nested].asOpt
println(result)

して結果が

Some(Nested(Example,content,List(Nested(ChildName,childContent,List()))))

わーい。
Json で設定ファイルとかできるでw