ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

オブジェクトリテラル内でのスプレッド演算子

 こんにちは。

 スプレッド演算子(spread operator)がオブジェクトリテラル内で使えませんでした。babel-preset-es2015入れとけばなんとかなるだろうと思っていたのですが、babel-preset-stage-2が必要みたいです。ECMAScriptの仕様策定方法を知らないのでstage-2の意味はわからないですが、なんかよさそうなものがあったので読もうと思います。

 ざっくりとした設定方法をメモしておきます。

インストール

npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-stage-2 webpack

webpack.config.jsはこんな感じになりました。

module.exports = {
  entry: './index.js',
  output: {
    path: __dirname,
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        loader:  'babel',
        query: {
          presets: [
            'es2015',
            'stage-2',
          ],
        },
      },
    ],
  },
}

以下動くかどうか確認のためindex.jsindex.htmlを用意。

index.js

let obj1 = { 'before': '...oh' };
alert(JSON.stringify(obj1,null,2));
let obj2 = { ...obj1 , 'after': 'oh!' };
alert(JSON.stringify(obj2,null,2));
// ひどいサンプル

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>Spread</title>
</head>
<body>
  <div id="root"></div>
  <script type="text/javascript" src="./bundle.js"></script>
</body>
</html>

webpackでビルド実行

./node_modules/.bin/webpack --colors --progress

 index.htmlをブラウザで開くとアラートが2回表示されます。オブジェクトリテラルが再代入なしで更新されているのが、なんとなくわかるかと思います。もっとプロパティが多いと、魅力が伝わる気がします。

感想

 ちゃんとした例を書かないとダメですね。あとECMAScriptに関しても知っておきたいです。

Ctags と vim と Git

概要

vimでタグジャンプを楽にする方法です。以下適当な翻訳です。

参考: Effortless Ctags with Git

Ctags はコードのインデックスを作成し, 関数, 変数, クラス, その他の識別子への Vim でのジャンプを容易にします. Gitのフックはリポジトリ単位です(Git hooks). あるリポジトリに対して, 指定されたフックをインストールするスクリプトを使用するのが推奨されていますが, 手作業で面倒です. テンプレを作成して楽しましょう.

テンプレートのフック作成

git全体で使用するテンプレートディレクトリを設定, 作成します.

git config --global init.templatedir '~/.git_template'
mkdir -p ~/.git_template/hooks

ctagsファイルを作成します.

vim .git_template/hooks/ctags
#!/bin/sh
set -e
PATH="/usr/local/bin:$PATH"
dir="`git rev-parse --git-dir`"
trap 'rm -f "$dir/$$.tags"' EXIT
git ls-files | \
  ctags --tag-relative -L - -f"$dir/$$.tags" --languages=-javascript,sql
mv "$dir/$$.tags" "$dir/tags"

上の内容は,

  • set -e: スクリプト内の各コマンドの実行でエラーが出たら処理を中止する
  • PATH..: 環境変数/usr/local/binを追加
  • dir...: gitリポジトリのパスをdir変数に格納
  • trap..: EXITシグナルを検知したら, 古いタグ .git/tags を削除する?
  • git...: git管理下のファイルに対しctagsを生成, jsとsqlは除く
  • mv ...: 生成されたタグをtagsディレクトリに移動

という感じです.

各フックファイルを作成します。pre-commitは以下です。

#!/bin/sh
.git/hooks/ctags >/dev/null 2>&1 &

post-checkout, post-mergeも内容は一緒です. 最後に rebase, commit --amend の対応として post-rewrite を作成します.

#!/bin/sh
case "$1" in
  rebase) exec .git/hooks/post-merge ;;
esac

これでいけるはずです。

結局5つのファイルを作成しました。

/Users/ushumpei/.git_template
|--hooks
|  |--ctags
|  |--post-checkout
|  |--post-commit
|  |--post-merge
|  |--post-rewrite

感想

Ctagsについて昔書いた文章が見つかったので載せてみました。

trapgit rev-parseがわかっていない...

Promiseのthenが素敵

 javascriptではes2015からPromiseが使えるようになります。Promiseで非同期処理を包むことで、非同期処理が終わったタイミングで次の処理を開始できて、コールバック地獄をなくす、等と言われていたりします。

 詳しい使い方は検索するとたくさん出てくるので割愛させていただいて、ちょっと気になったことを書いていきます。

 以下、サーバへ非同期で通信し、jsonデータをもらって、表示するコードです。主な動きとしては;

  1. 2000ms待つ。
  2. サーバへ非同期なGETリクエストを送信。
  3. レスポンスのJSON文字列をオブジェクトに変換。
  4. オブジェクトの情報を加工して画面に描画。

です。

app/index.js

const wait = ms => {
  return new Promise((resolve, reject) => {
    console.log(`wait ${ms}ms...`);
    setInterval(_ => {
      resolve('OK!');
    }, ms)
  });
}

const fetchData = url => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);

    xhr.onload = () => {
      if (xhr.readyState === 4 && xhr.status === 200) {
        resolve(xhr.response);
        return;
      }

      reject(new Error(xhr.statusText));
    };

    xhr.onerror = () => {
      reject(new Error(xhr.statusText));
    };

    xhr.send(null);
  });
};

const renderHoges = data => {
  const root = document.getElementById('root');
  root.innerHTML = '';

  data.forEach(item => {
    let node = document.createElement('div');
    node.innerText = `${item.id}: ${item.hoge}`;
    root.appendChild(node);
  });

  return data.length;
};

wait(2000)
.then(_ => fetchData('/api/hoges'))
.then(JSON.parse)
.then(renderHoges)
.then(length => console.log(`${length} hoges rendered!`))
.catch(error => console.error(error));

app/static/index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>Promise</title>
</head>
<body>
  <div id="root">loading...</div>
  <script type="text/javascript" src="bundle.js"></script>
</body>
</html>

サーバ側はここから見れます。

 嬉しいなと思ったのは、thenを使うことで、もともとPromiseを考慮していないJSON.parserenderHogesなどの同期処理をチェインできることです。

 つまり明確に非同期な処理だけPromiseで書けばよく、チェインさせたいがために同期処理のPromise版を書く必要がないということです。

感想

 何当たり前のこと言ってんの?と思われるかもしれないですね。

 困ったのは、Promiseから値を取り出す方法はあるのだろうか?、ということです。それを必要としている時点で処理の設計を間違えているのだろうか?とりあえず、外側で宣言した変数に再代入させる方法は上手くいきませんでした。reduxでサーバとやりとりする際にaction creatorの関数の中にPromiseを使った非同期通信を書いた時に、レスポンスの中身が取り出せない。。。

haskellのApplicative laws - composition

 こんにちは。

 すごいHaskellたのしく学ぼう!の11章に出てくるアプリカティブ則の一つ、「composition則」について何を言っているかを考えてみました。

composition則

 Applicative型クラスを継承するデータ型は、関数を実装すること以外にも、実装した関数が満たさなければいけない規則が存在します。これを確認するのは設計者に委ねられています。Applicative型クラスでは4つの法則が存在します。ここではその4つのうちの一つ「composition則」(正式名称不明)について考えてみたいと思います。ちなみに4つの法則はBasic librariesのリファレンスControl.Applicativeのページに載っています。

 「composition則」は次で定義されています;

pure (.) <*> u <*> v <*> w = u <*> (v <*> w)

 なぜこの法則を満たさなければいけないのでしょうか。ここでは関数合成に対して、「アプリカティブファンクターに包まれた合成演算子(.)を使って関数合成を行うことと、<*>を使って関数合成を行うことは同じか?」ということが成り立って欲しいようです。単なる想像ですが、既存に存在している合成演算子(.)と新しい合成演算子<*>の間にある種の整合性を保っておきたいように見えます。composition則はそのことを確かめましょう、といっています。

 composition則の定義を見ると、左辺がごちゃごちゃしています。適応の順を整理していきましょう。

pure (.) <*> u <*> v <*> w
-- = ( pure (.) ) <*> u <*> v <*> w
-- = ( ( pure (.) ) <*> u ) <*> v <*> w
-- = ( ( ( pure (.) ) <*> u ) <*> v ) <*> w :

実際に適用して行ってみましょう。

-- u, v は以下;
-- u :: Num a => Maybe (a -> a)
-- v :: Num a => Maybe (a -> a)

ghci>:t pure (.)
pure (.) :: Applicative f => f ((b -> c) -> (a -> b) -> a -> c)
-- まず合成演算子(.)がpureによってアプリカティブファンクターに包まれます。

ghci>:t pure (.) <*> u
pure (.) <*> u :: Num c => Maybe ((a -> c) -> a -> c)
-- 次に<*>で、アプリカティブファンクターに包まれた合成演算子の、
-- 第一引数の関数としてuを渡します。

ghci>:t pure (.) <*> u <*> v
pure (.) <*> u <*> v :: Num c => Maybe (c -> c)
-- 再び<*>で、アプリカティブファンクターに包まれた合成演算子の、
-- 第二引数の関数としてvを渡します。

ghci>:t pure (.) <*> u <*> v <*> Just 1
pure (.) <*> u <*> v <*> Just 1 :: Num b => Maybe b
-- 最後に完成したアプリカティブファンクターに包まれた関数に対し、
-- <*>でアプリカティブ値を渡します。

左辺はこれで終わりです。右辺は<*>で関数適用をチェインしているだけなので割愛です。

なぜ必要なのか?

 これに関してははっきりとしたことはわかりませんでした。composition則が何を保証したいかは、結合演算子がどんな関数にも使えることに関係してくるのではないかと思うのですが自信はないです。調べたいと思います。

Vimで折畳

こんにちは。

Vimについて書きます。

概要

Vimでは文章を折りたたむことができるようです(Vi には折畳は無い)。htmlを編集している時など、ファイルが長くてちょっと読みづらいといった時にとても便利です。

Vimユーザマニュアルはとても素晴らしいので、ここにあれこれ解説を書く意味もないかと思います。なのでここでは、コマンドとその動きとかを軽く書こうと思います。Vimを起動した状態で:help fold:help usr_28.txtを実行すると関連するドキュメントを読むことが出来ます。またwebの翻訳も利用可能です。

参考 参考

コマンド

折りたたみ関連のコマンドの多くはzで始まります。基本的なものは以下です。

コマンド 内容
zf 折り畳む (Fold)
zo 折り畳みを開く (Open)
zc 折り畳みを閉じる (Close)
za 折り畳みの開く閉じるを切り替える (Alter?)
zd 折り畳みを削除する(Delete)

zfはオペレータなので、)2jなどのモーションか、itipなどのテキストオブジェクトを後ろにくっつけて使用します。

f:id:ushumpei:20160730161923g:plain

他にもファイル全体の操作もあります。

コマンド 内容
zr すべての折り畳みを開く(減らす) (Reduce)
zm すべての折り畳みを閉じる(増やす) (More)

zr,zmはすべての折り畳みに対する操作ですが、あくまで現在表示されているものが対象になります。つまり入れ子になっている折り畳みを開いたり閉じたりは出来ません。この時に使用するのがzR,zMです。これらは再帰的に折り畳みに作用します。同様に、o,c,a,dも大文字にすることで再帰的に操作を行います。例えばzR再帰的にすべての折り畳みを開くので、結果すべての折り畳みを開きます。zMと交互に使うのが楽かもしれないです。

あと、折り畳み間を移動するのに便利なコマンドです。

コマンド 内容
zj 画面下方向の次の折り畳みへ移動。
zk 画面上方向の次の折り畳みへ移動。
[z 現在開いている折り畳みの先頭へ移動、すでに先頭の場合はその外側の先頭へ移動、すでに一番外側の折り畳みなら何も起きない。
]z 現在開いている折り畳みの末尾へ移動、動作は[zと同様。

疑問

折りたたまれている情報はどこにある?

マニュアルによると、ファイルを破棄すると折り畳みの情報は失われてしまうそうです。折り畳みの情報を保存するコマンドはmkview、呼び出すコマンドはloadviewです。

保存されたファイルはset viewdirコマンドで表示されるディレクトリ内で確認できます。ファイルを開いてみるとローカル変数の定義の後に以下のような記述が見つかりました。数字を変えたら折り畳み位置が変わりましたのでこれが保存された設定値だと思います。

...
3,6fold
8,21fold
...

感想

保存について書きましたが、折り畳みを保存して呼び出して使うのは現実的ではないと思います。めんどくさいです。htmlやコードは構造がはっきりしているため、自動的に折り畳みを定義できるはずで、実際そういう設定がVimにはあるようです。

set foldmethodで現在の設定が確認できます。現在はmanualになっているので、これは手動で折り畳みを定義するデフォルトの設定なようです。

この他指定可能な値は以下になるようです。

内容
manual 折り畳みは手動で設定する。
indent 等しいインデントの行で折り畳みを作る。
expr オプションfoldexprで深さを設定する。
marker マーカーで折り畳みを指定する。
syntax 構文強調表示のキーワードを使って指定する。
diff 変更されていないテキストを折り畳む。

とりあえずset foldmethod=indentvimrcに設定して様子を見ます。ただしこれを設定すると開くファイルがことごとくデフォルトで折り畳まれてしまっています。これは結構面倒臭いのでset foldlevel=100とか書いておくと初期表示時に折り畳まれなくなります(なんか乱暴ですね...)。

以上です!

javascriptでpartition 関数を実装

こんにちは

javascripthaskellでいうところのpartition関数を実装してみたのでメモします。

partition関数

全然一般的ではないので説明です。僕がpartition関数って言っているのは、「配列を、その要素に対して真偽を判定する関数により、真なものと偽なものの2つのグループに分ける関数」です。

たとえば以下のように動くものです。

[0,1,2,3,4,5,6,7,8,9].partition(num => num > 4)
// => [[5,6,7,8,9],[0,1,2,3,4]]

[1,"2",3].partition(item => typeof item === 'string')
// => [["2"],[1,3]]

いかにもありそうな関数ですが、探した限りではありませんでした。(altjsでは実装されている場合があるようです)

やっちゃだめみたいですがArrayのprototypeを汚染して関数を定義します。Arrayの他のコールバックを引数に取る関数を参考にしました。

Array.prototype.partition = function(callback, thisArg) {

  if (this === null) {
    throw new TypeError('Array.prototype.partition called on null or undefined');
  }

  if (typeof callback !== 'function') {
    throw new TypeError('callback must be a function');
  }

  var T;
  if (thisArg) {
    T = thisArg;
  }

  var list = Object(this);
  var length = list.length >>> 0;
  var value;

  var accepted = new Array();
  var rejected = new Array();

  for(var i = 0; i < length; i++) {
    value = list[i];
    if (callback.call(T, value, i, list)) {
      accepted.push(value);
    } else {
      rejected.push(value);
    }
  }

  return [accepted, rejected];
};

[0,1,2,3,4,5,6,7,8,9].partition(num => num > 4)
// => [[5,6,7,8,9],[0,1,2,3,4]]

[1,"2",3].partition(item => typeof item === 'string')
// => [["2"],[1,3]]

第二引数のthisArgArray.prototype.mapの仕様にあったため追記しました。使い道があまりわかりませんが例えば繰り返しの中で副作用を起こさせることができます(ちょっと意味のない例。。。)。

追記(2017/11/29): よく考えるとthisArgは関数呼ぶ時に呼び元のthisを渡したりする時に使うためでした。

[1,2,3,4,5].partition(function(num) {
  this.log(num) ;
  return num > 2;
}, {
  log(num) { console.log(`${num}を振り分けました`) } 
});

最後にreduceを使って、配列とコールバックを引数に取る関数として書いてみます。

const partition = (list, callback) => {
  if (list === null) throw new TypeError('partition called on null or undefined');
  if (typeof callback !== 'function') throw new TypeError('callback must be a function');

  return list.reduce((state, item) => {
    if(callback(item)) {
      state[0].push(item);
    } else {
      state[1].push(item);
    }
    return state;
  }, [[],[]]);
};

partition([0,1,2,3,4,5,6,7,8,9], num => num > 4)
// => [[5,6,7,8,9],[0,1,2,3,4]]

partition([1,"2",3], item => typeof item === 'string')
// => [["2"],[1,3]]

感想

テストとか書いてしっかり確かめたいですね。小さいものは書いていて楽しいです。

browser-syncでブラウザ自動更新

Node.jsでコードを書いていると、ターミナルとブラウザの行き来が頻発して面倒です。自分のノートPCはモニタが小さいので、ウィンドウを切り替えていると埋もれてしまい、それを探すために集中力が切れてしまったりします。

browser-syncを使ってコードを書き換えるとブラウザが自動更新されるようにしてみました。expressと連携することもできるので、そのこともメモしておきます。

単純な使い方

npm install --save-dev browser-sync

監視対象のファイルを指定して起動します。

./node_modules/.bin/browser-sync start --server --files index.html 

コマンドを実行するとlocalhost:3000でサーバが起動します。ブラウザが立ち上がり、Connected to Browser Syncという文字がページ右上に表示されます。この状態で、index.htmlを編集するとブラウザが自動更新されます。


try browser sync

expressと連携

expressでサーバを立てている場合、connect-browser-syncミドルウェアを利用してサーバに自動更新の機能を組み込むことができます。まずはインストールします。

npm install express --save
npm install browser-sync --save-dev
npm install connect-browser-sync --save-dev

app.jsを作成します。

var express = require('express');
var app = express();

if ( app.get('env') === 'development' ) {
  var browserSync = require('browser-sync');
  var connectBrowserSync = require('connect-browser-sync');

  var browserSyncConfigurations = { "files": "static/*" };
  app.use(connectBrowserSync(browserSync(browserSyncConfigurations)));
}

app.use(express.static(__dirname + '/static'));

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/static/index.html');
});

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

app.listen(3000);

ifの部分がbrowserSyncの設定です。オプションをオブジェクトでbrowserSync関数に渡し、connectBrowserSyncミドルウェアをexpressに登録しています。オプションのfilesは監視対象のファイルを設定します。ワイルドカードで指定したり、配列として複数のパスを渡すこともできます。ここではstatic以下のファイルをすべて監視しています。ここをコンパイル後のjsの吐き出し先に設定したりすれば、webpackと協調して使うこともできますね。 ミドルウェアの登録のタイミング次第では動かなかったりして少しはまりました。静的コンテンツのディレクトリ設定をbrowserSyncの前に設定したら監視が始まりませんでした。

感想

browserSyncで検索すると大体はgulpと一緒に使おうみたいな記事が見つかります。設定ファイルの記述方法を覚えるのが大変なので、gulpはやらなくていいかなと思い、自動更新に絞った使い方を調べました。

上記二つのケースどちらでも、browserSyncを起動すると管理サーバも立ち上がるのですが、その使い方があまりわかっていません。また「snipetを貼り付けてね」みたいなことをbrowserSyncから注意されるのですが、これが何に使われているかわからないです。自動更新できているから、ひとまず放置しています。

追記: ブラウザ同士のイベントを同期することもできるみたいです。同一ネットワーク内だと同期されるのかな?

圏, 関手, 自然変換

圏論の定義メモ

Def.圏(category)

 C は次のデータからなります;

  • 対象(objects)
    •  A,  B,  C...
  • 射(arrows)
    •  f,  g,  h...
  • ドメイン(domain), コドメイン(codomain)
    • 任意の射  f に対し, 対象  dom(f),  cod(f) が定まる. この時  f : A \rightarrow B と表す. (ただし  A = dom(f) B = cod(f)
  • 合成(composite)
    • 任意の射  f : A \rightarrow B g: B \rightarrow Cに対し、 h = f \circ g: A \rightarrow C という射が定まる.
  • 恒等射(identity arrow)
    • 任意の対象  A に対し,  1_A という射が定まる.

これらのデータは次の法則を満たします;

  • 結合律(associativity):
    • 任意の射  f,  g,  h cod(f) = dom(g),  cod(g) = dom(h)を満たすものに対し,  h \circ (g \circ f) = (h \circ g ) \circ f が成り立つ.
  • 恒等律(unit):
    • 任意の射  f: A \rightarrow B に対し,  f \circ 1_A = f = 1_B \circ f

Def.関手(functor)

 C,  D に対し, 関手  F : C \rightarrow D とは, 圏  C の対象を圏  D の対象に, 圏  C の射を圏  D の射に写すもので, 次を満たします;

  •  F(f : A \rightarrow B) = F(f) : F(A) \rightarrow F(B)
  •  F(1_A) = 1_F(A)
  •  F(g \circ f) = F(g) \circ F(f)

Def.自然変換(natural transformation)

 C,  D , 関手  F, G : C \rightarrow D に対し, 自然変換  \eta : F \rightarrow G とは, 圏  C の任意の対象  A に対し, 圏  D の射  \eta_A: F(A) \rightarrow G(A) を与えるもので, 次を満たします;

  •  C の任意の射  f: C \rightarrow \acute{C} に対し,  \eta_{\acute{C}} \circ F(f) = G(f) \circ \eta_C が成り立つ.

感想

だからどうしたという感じですよね。写像だ、とか集合だ、とか限定すると間違ってしまうためぼんやりした定義になってしまいます。はてなの所為なのか可換図式書けませんでした...

PCのカメラを起動する

WebRTCで遊んでみたいので、手始めにPCの内臓カメラを起動するだけのページを作成します。

navigatorオブジェクトのgetUserMediaメソッドを使用することでデバイスにアクセスできるみたいです。ただ、ブラウザ環境ごとにこのメソッドがあったりなかったりするため、代替となる関数を列挙してそのうちあったものを使用する、というコードを書きます。

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia || navigator.msGetUserMedia;

メソッド自体はこんな形をしています。

navigator.getUserMedia(constraints,successCallback,errorCallback)

次にこのAPIを使用してメディアに接続します。

    navigator.getUserMedia({video: true, audio: true},
    stream => {
      video.src = window.URL.createObjectURL(stream);
    },
    error => {
      console.error(error);
      return;
    });

あとは適当にhtmlをかいた、ら動くと思ったのですが、エラーも吐かずになぜか動かない。

そういえばwebサーバに置かないとダメ、みたいなことを聞いた気がしたので、nodeでexpressを使ってサーバを立てました。

mkdir webrtc
cd webrtc
npm init -y
npm install express

二つのファイルを作成します。

server.js

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html');
});

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

app.listen(3000);

index.html

<html>
  <head>
    <title>sample</title>
  </head>
  <body>
  <video id='video' autoplay></video>
  <script type="text/javascript">
    let video = document.querySelector('video');
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

    navigator.getUserMedia({video: true, audio: true},
    stream => {
      video.src = window.URL.createObjectURL(stream);
    },
    error => {
      console.error(error);
      return;
    });
  </script>
  </body>
</html>

あとは起動してlocalhostの3000ポートにアクセスします。

node server.js

f:id:ushumpei:20160717043812p:plain

なんか暗いですが映りました!

感想

getUserMediaがPromise化対応したそうですが、chromeはダメみたいです。

近々reduxコンポーネントとして、動画の録画、再生、停止、保存機能を持った部品を作成したいです。

あと通信部分で、同一LAN内の携帯とPCとかならビデオチャットできないだろうか?と考えています。

オーダー

オーダーについて。適当に済ましていたので、おぼえがきします。アルゴリズムでも数学でも見ることがよくありますが、若干うろ覚えです。

定義

 { f(x) } { x \rightarrow \infty }のときオーダー { O(g(x)) }である。

 { :\Longleftrightarrow }

 {}^\exists x_{0}, {}^\exists M > 0 \quad s.t. \quad {}^\forall x > x_{0} \Longrightarrow \vert f(x) \vert \lt M \vert g(x) \vert

これを変形すると、 { \lim_{ x \rightarrow \infty } \left\vert \frac{ f(x) }{ g(x) } \right\vert \lt \infty } となることから、この定義は  { f(x) } { g(x) } より発散する速度が遅いということを意味しているのがわかります。この時  f(x) g(x) で抑えられる、と言ったりするようです。

これに対し似た記法で、 f(x) = o(g(x)) \quad x \rightarrow \inftyというものもあります。この時、以下が成り立ちます。

 { \lim_{ x \rightarrow \infty } \left\vert \frac{ f(x) }{ g(x) } \right\vert = 0 }

詳細な定義は省略しますが極限が0になることが違います。  f(x) g(x)より発散する速度が、 O(g(x)) の時より、十分遅いというイメージです。この時  f(x) g(x) に比べ無視できる、と言ったりするようです。例えば、写像  { f : { \mathbf R }^n \longrightarrow { \mathbf R }^m } {\bf x } = {\bf a } で全微分可能とは、

 { {}^\exists A : n \times m \, matrix \quad s.t. \quad f({\bf a} + {\bf h}) = f({\bf a}) + A {\bf h} + o(\vert\vert {\bf h} \vert\vert) }

です。ここでは  {\bf h} \rightarrow 0 となっていて多少変化がありますが基本的に意味は変わっていません。つまり、 f({\bf a} + {\bf h}) f({\bf a}) + A {\bf h} {\bf h} のノルムが十分小さいところでは限りなく等しいということが言えます。

アルゴリズムなどではよく、 O(n) O(\sqrt{n}) などと言ったりしますね。これらは「入力データ量  n に対する実行時間は  O(n)」みたいな文脈だったと思います。これはつまり、

  \lim_{ n \rightarrow \infty } \left\vert \frac{ \text{ アルゴリズムの実行時間 } }{  (n: \text{入力データ量} ) } \right\vert = const \lt \infty

より、

 \text{ アルゴリズムの実行時間 } =  const \times (n: \text{入力データ量})

この場合はアルゴリズムの実行時間が  n に比例する、ということですね。 n^2 なども同様です。

感想

わかったようなわかってないような微妙な気分です。当たり前のことを言っている気持ちにもなりました。

まあ少なくとも毎回ググらなくてよくなっただけ、進歩かと思います。

javascriptで実行時間を表示する

短いメモです。

console.timeconsole.timeEndを使うとスクリプトの実行時間を表示することができます。

var loop = n => {
  console.time('timer');
  for(i = 1; i <= n; i++) {
    for(j = 1; j <= n; j++) {
      console.log(`${i} x ${j} = ${i*j}`);
    }
  }
  console.timeEnd('timer');
}

引数で与えている文字列を使って、スタートとエンドを対応させます。

ここを参考にしました[JavaScript]使い分けるだけで今すぐデバッグ効率を上げる、consoleオブジェクトの関数 - Qiitaconsoleオブジェクトの関数がたくさん書かれています。

ReduxとExpressかElectronか

Reduxのチュートリアルを見終わったので、実際に手を動かしてみようと思い、リポジトリを作成してみました。中身はExample: Todo List | Reduxです。

github.com

expresselectronで動作確認ができます。

感想

写経しているとreduxに関して徐々にわかってきました。reduxは画面状態をStore内のstateオブジェクトとして持っていて、操作によって発行されるactionオブジェクトとstateをセットで、Reducerに渡すことで、新たなstateを取得します。 { \displaystyle  (state, action) \longmapsto state}

今回の登場人物は、

  • Component(presentation, container)
  • Action Creator
  • Reducer & Store

処理の流れもこの順番です。

画面はコンポーネントComponent)のツリー構造で表現されます。コンポーネントにはPresentation ComponentContainer Componentの二種類があり、Presentation Componentは構造を、Container Componentは状態を変化させる方法を定義します。単独で部品としても使えますが、Container Componentで定義した状態を変化させる関数を、react-reduxライブラリに含まれるconnect関数を使って、Presentation Componentに結びつけて使用したりもできます。また、このconnectによってStoreComponentの結びつけも行なっているようです。(ちょっと調べないと、です)
また、コンポーネントのツリーの頂点にProviderというreact-reduxライブラリに含まれるコンポーネントを追加しているので、ここが状態をツリーの枝に伝える仕組みを提供しているのかもしれないです。

特定の動作に対して発行するActionAction Creatorで定義しておきます。これは最低限typeというプロパティを持ったオブジェクトを生成すれば問題ないようです。

ReducerStoreを定めているのだろうという認識で、この二つは同じ行に書いています。(実装的な視点、ですかね)Reducerは古いstateと、発行されたactionを引数に新しいstateを返します。reduxライブラリのcreateStore関数によってReducerからStoreが生成されます。

いろいろ書きましたが、それぞれの部品はわかるものの、連結部分がわかりにくいという感想です。

知らなくてはいけないのはreact-reduxProviderconnectによっていかにコンポーネントStoreを結びつけているか、という部分ですかね。

Reduxの勉強3

前々回

前回

引き続き、Reduxのレッスン動画を視聴した時のメモです。

  • 21: ToDoアプリのリファクタリング。見た目と挙動を分けます。Main container componentからPresentational componentを分離しましょうというはなし。
  • 22: container componentは振る舞いを定義するクラスとして作成した。conponentDidMountconponentWillUnmontメソッドを定義し、presentational componentは状態に対する見た目だけを定義する。のかな?
  • 23: Storeと結びついているコンポーネントforceUpdateする?renderを全体のコンポーネントから分割したコンポーネントに行わせるように修正した。(しかしAddToDoコンポーネントにはrenderがないようだが)厳密にPresentationとContainerを分割する必要はないが、したほうがいいと言ったことを言っている気がする。。。

(だんだんきつくなってきました。。。)

  • 24: StoreにアクセスするコンポーネントがContainerコンポーネントみたいだ。子のContainer ComponentにStoreを渡すために一旦storeをトップレベルの引数として渡す処理を書いた。
  • 25: Providerを使うことでPresentation ComponentからStoreを取り除くことができるみたいだ。ContextによってContainer ComponentにStoreを渡すことができるようになった。Contextを使うにはchildContextTypesを指定しなければいけない。グローバルにアクセスできる感じか。ただしContextはあまり安定していないらしく、がっつり使っているのは良くないとのことです。
  • 26: Providerはライブラリとして取得できるよ、という説明と記述方法でした。
  • 27: ReactReduxライブラリのconnectメソッドを使うことでContainer Componentを作成することができる。最終的にどうなるか知れればいいかなという気分になってきました。
  • 28, 29: connectメソッドを使って色々整理していきます。
  • 30: ActionCreaterについて。

だいぶ聞き取れず、試すこともできず、停滞しています。 後日初めから、アプリを作成しつつ追っかけていこうと思います。。。

webpack、babel、React

Reactの環境構築です。できるだけ覚えることを減らしたいので、webpackbabelreactを軸に必要最低限なものをインストールします。Node.jsの環境が整っている前提です。(npmコマンドが使えればOKかと思います)

それぞれに関するメモです。

  • webpack: jsxとかes6記法で書いたスクリプトとかをクライアント側に送るためにまとめるビルドツールという認識です。モジュール間の依存性を解決しつつビルドしてくれるそうです。チュートリアルやったらわかった気になれました。loaderというモジュールを追加することで、jsファイルだけでなくcssなどのまとめ方も指定できます。
  • babel: es6記法を一般的なブラウザで読めるようにコンパイルするもの。webpackでes6記法を含んだファイルをビルドする際に、エンジンとして使いました。インストールのみで特に何もしていないです。
  • react: jsのテンプレートエンジンです。jsxとして書くのが楽なので書くと、そのままではブラウザで動きません。なのでwebpackで普通のjsファイルにビルドさせます。

設定

パッケージファイルを作成し、必要なパッケージをインストールします。

npm init -y
npm install webpack babel-loader babel-core babel-preset-es2015 babel-preset-react react react-dom --save-dev

次はwebpackの設定です、設定ファイルを記述しない場合webpackにいろいろオプションを指定して実行することになりますので、ファイルwebpack.confing.jsを作成します。

webpack.config.js

module.exports = {
  entry: "./entry.js",
  output: {
    path: __dirname,
    filename: "bundle.js"
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loader: "babel",
        query: {
          presets: ['es2015', 'react']
        }
      }
    ]
  }
};

このファイルにwebpackコマンド実行時の設定をオブジェクトとして記述していきます。プロパティの説明をします。

  • entryがビルドしたいスクリプトになります。この例ではentry.jsと設定しています。内部でrequireとか呼び出ししているファイルは、webpackが勝手にまとめてくれます。
  • outputには出力ファイルのパスと名前を記述します。ディレクトリ構造を考えていないので特にパスは指定してません。
  • moduleloadersという配列に、どのファイルをどのようにビルドするかの設定をオブジェクトで記述します。今回は一つだけです。
    • testにはどのファイルを対象にするかを正規表現で記述します。今回は拡張子がjsまたはjsxのものを対象にします。
    • excludeには除外するもののパターンを記述します。
    • loaderはビルドするエンジンを指定しているのだと思います。
    • loaderに機能を追加するのがpresetなんだろうか。presetsはes6記法とreactに関するものを指定しました。

次に、順番が前後していますが、entry.jsとReactのコンポーネントと動作確認用のindex.htmlを作りましょう。

entry.js

window.onload = () => {
  require('./Hello.jsx');
}

Hello.jsx

const React = require('react');
const { render } = require('react-dom');

const Hello = React.createClass({
  render: function() {
    return (
      <div className="hello">
        Hello, world!
      </div>
    );
  }
});
render(
  <Hello />,
  document.getElementById('root')
);

index.html

<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <script type="text/javascript" src="bundle.js" charset="utf-8"></script>
    <div id="root"></div>
  </body>
</html>

あとはコマンドを叩くだけです。

./node_modules/.bin/webpack

実行完了したらindex.htmlをブラウザで確認してみてください。Reactっぽさはないですが、レンダリングされているのが確認できると思います。

必須ではないですがコマンドの実行はpackage.jsonscriptsに記述しちゃうと楽です。

package.json

{
  "name": "webpack-tutorial",
  "version": "1.0.0",
  "description": "",
  "main": "bundle.js",
  "dependencies": {
    "webpack": "^1.13.1",
    "css-loader": "^0.23.1",
    "style-loader": "^0.13.1",
    "babel-core": "^6.10.4",
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-react": "^6.11.1",
    "react": "^15.2.0",
    "react-dom": "^15.2.0"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "webpack": "webpack --progress --colors"
  },
  "author": "",
  "license": "ISC"
}

以下で起動できるようになります。

npm run webpack

以上です。コードはgithubに上げました。リポジトリ名がチュートリアルとなっていますが全然チュートリアルではないですが。。。

感想

ビルドツールのノリが少しわかりました。ビルドツールが自分にとって身近ではないのは、頻繁にビルドしないからに尽きるんでしょうね。

ともあれようやくReactが動いたので、Reduxのチュートリアルを試すことができます。

Reduxの勉強2

前回

動画が30分で終わるかと思ったら30回あることに気がついて力尽きてしまったので、今日はその残りを見ていきます。

Webpackを使えるようになろうとか言っていましたが、いまの腰を据えて試せていないので停滞しています。残りの動画を放っておくとちょっと分かった気になっているので見なくなる可能性があります、こちらを優先させていただきます。

  • 11: todos Reducerをテストファーストで書いた。actionにidがふってあるが、どこまでふったか、stateかどこかに数字を控えなければいけないのだろうか?(後の動画でグローバル変数として保持しているのがわかる)
  • 12: todos Reducerに「ADD_TODO」だけではなく「TOGGLE_TODO」メソッド(case?すくなくともメソッドではない)を追加。副作用なくすためにしっかりテスト書かないとダメ。ちょっと性善説で悩む(でもみんな責任感あるし大丈夫かな)。
  • 13: Reducerの分割。stateのリストを受け取るReducerの内部を、単一のstateを受け取るReducerに切り出す。どんどんReducer同士を結合させちゃえてきな英語を喋っていた気がする、この辺りは副作用のない関数であることが不安を取り去ってくれてますね。想定していないtypeのActionに関してはそのままstate返しましょう、という念押し。
  • 14: Reducerの合成だが、ちょっと難しい。todosとは別のvisibilityFilter Reducerを追加し、それらを包含したtodoApp Reducerを作成。todoApp内部で、各Reducerへの振り分けを行なっているみたい。なんかStoreとReducerの関係性が曖昧になってきた。。。ActionをStoreにdispatchした際に、入れ子になったどのstateに対するActionか指定していないが、これは対象としていない方にundefinedが渡るからシカトしてOKということか?なんか違和感。
  • 15: Reducerの合成はcombineReducersを使うと楽と言っている。またes6の記法で定義した変数a, b, cobj = {a,b,c}と書けばオブジェクトのkey valueが勝手に入るらしい。「object literal shorthand anotation」だそうです。
  • 16: combineReducers の実装を書いて説明してくれる。reduceで少し詰まった。多分、foldlとかと同じでいいんですよね。配列の各要素を使って一つのものをどんどん作っていくイメージをしました。
  • 17: Reactを使ってToDoの「ADD_TODO」機能のユーザインタフェースを作った。また、入力から出力までのReduxの(?)ライフサイクルを説明してくれているので、よくわからなくなったらこれを見るといいかも。
  • 18: 「TOGGLE_TODO」機能をUIから使えるようにした。全体的に言えるのはどの関数も、基本的には全てのstateを総なめして一致したら処理を実行する感じみたいだ。
  • 19: 「visibilityFilter」のUIを作成。画面側の機能とReducerは対応していないという当たり前のことに気がつく。filterをかける処理などは通常の関数で実装しているが、もし自分が作った時にその辺間違えそう。画面表示とstateの違いをちゃんと整理しておかないと危険ですね。
  • 20: ToDoアプリのリファクタリング。Reactコンポーネントの分離について。分離の基準がよく理解できない。イベントハンドラのコールバック関数はどちらが持つべきか等。分離の途中で次回。

感想

本当は今日中に30まで見てしまって、手を動かす時間を取りたかったのですが、眠気が襲ってきてしまったのでこれで終了です。

動画の中で、コンポーネント内でinputの値を取得するために、react callback ref apiを使っていた。常識っぽいので知っておきたいです。

あと、markdownのlistはoffsetが効かないため困りました。今日は動画を11から見始めたので、

11. hogehoge
12. hogehoge
...

と書いていたのですが、画面上では

1. hogehoge
2. hogehoge
...

になってしまい、ちょっと面倒さを感じながら*をかませて対応しました。