My Brain is Open.

思いついたことを適当に列列と

数学勉強会:2017-02-09 集合と命題

ただいま社内でこちらの本を使って数学勉強会を開催中。

論理と集合から始める数学の基礎

論理と集合から始める数学の基礎

振り返りを兼ねて、内容を記録しておきます。 ものすごく端折って書くので、きちんと勉強する方は上記の書籍や自分がわかりやすい書籍を購入するなどして学ぶことをオススメします。

続きを読む

関数型プログラミング言語Elmのススメ

Elmとは?

最近、JavaScriptのトランスパイラが色々ありますよね。CoffeeScriptとかTypeScriptとか、更にそれを取り巻くwebpack, gulpなどのエコシステム…すごい勢いですね。

そんな中で、Elmという言語はとても硬派な部類に入ると思います。他の軟弱なJavaScriptライブラリなどとは無縁のままで一匹狼を貫き通すような…。 そんな僕の感想は置いておいて、ElmはHaskellライクな文法と厳密な関数型プログラミングでバグのないクライアントサイドアプリケーションを構築できます。

ひとまず実際に構築されたアプリに触れてみたい方は以下のToDoアプリやサンプル集を試してみて下さい。

ElmはFluxフレームワークの中で現在人気のあるReduxでも言及されているように、そのアーキテクチャは学ぶべきものがありますので多少触れてみるとコーディングの質の向上につながるかもしれません。

Elmのアーキテクチャ

今回BMIを計算するサンプルコードを作ってみたので、ソースコードに触れながらElmのアーキテクチャを見ていきましょう。

BMI計算機 by Elm 0.18 · GitHub

動作するサンプルはこちら

オンラインで試す場合は オンラインエディタ の左側にコードを貼り付けて Compile を実行すると動作します。

ローカルマシン上でコンパイルする場合は、インストール作業後、以下のコマンドでJavaScriptを含むHTMLファイルに変換できます。 生成される index.html をブラウザで開いて下さい。

$ elm-make BMI.elm --output index.html

main

プログラムを動かす構成要素は model, view, update の3つ。シンプルですね。

main = 
  Html.beginnerProgram
    { model  = initialModel
    , view   = view
    , update = update
    }

model は本当にただのデータです。振る舞いなどは一切含んでいません。 view : model -> Html msg はモデルのデータをHTMLに変換します。表現のみを担当していて、モデルのデータを更新することはできません。 update : msg -> model -> model は何らかのアクションに応じて、現在のモデルから新しいモデルへと変換を行います。HTMLなどの表現には一切触れません。 この3つが組み合わさることで、次のようにプログラムは動作します。

f:id:mather314:20161129180930p:plain

注目すべき点はデータを直接いじって変更するのではなく新しいモデルを生成していることで、モデルそのものは不変(immutable)であることです。 モデルで定義可能な状態がアプリケーションが持ちうる状態の全てであり、それ以外の状態は起こりません。また、 update 以外の方法でモデルが新しいモデルになることもありません。cf. 有限オートマトン - Wikipedia

モデル

今回の場合、モデルの中に含まれる情報は2つ、身長と体重だけです。

type alias Model =
  { height : Float
  , weight : Float
  }
  
initialModel : Model
initialModel = 
  { height = 171.5
  , weight = 65.5
  }

JavaScriptとは違い、 undefined などは指定できません。「型は Float だが値がない可能性がある」という場合は、 Maybe Float という型になります。

View

view : Model -> Html Msg
view model =
  let
    h = model.height / 100 -- メートルに変換
    bmi = model.weight / ( h * h ) 
  in
    div [] [
      form [] [
        heightInput model.height,
        weightInput model.weight
      ],
      p [] [ text ("BMI: " ++ (toString bmi)) ]
    ]
    
heightInput : Float -> Html Msg
heightInput h =
  let
    heightAttributes t = 
      [type_ t
      , value <| toString h
      , A.min "100.0"
      , A.max "250.0"
      , step "0.1"
      , onInput (updateFloat UpdateHeight)
      ]
  in
    p [] [
      label [] [text "身長"],
      input (heightAttributes "range") [],
      input (heightAttributes "number") [], text "cm"
    ]

一部省略しましたが、 view 関数の定義です。 BMI値の計算は let の中で行われ、変数代入ではなく「束縛」されます。hbmi の値は更新することができません。

続いて in で、束縛した値を用いてHTMLのパーツを定義しています。 身長と体重の入力部分はそれぞれ身長と体重の値しか用いないので、1変数のコンポーネントとして分解しました。

heightAttributes 関数はHTMLの <input> タグで使われる属性値のリストを表しています。数値の入力に関して制限をしているのと、 onInput によって「入力値が変更された場合に送信する msg 」を定義しており、updateFloat UpdateHeight は最終的に UpdateHeight 175.0 のような値を送信する想定です。

ところが、この onInput で渡される値は、数値に制限しているにも関わらず文字列 String となってしまうので、 UpdateHeight に渡す前に Float に変換する必要があります。 そのための関数が updateFloat です。

updateFloat : (Float -> Msg) -> String -> Msg
updateFloat updater str =
  case decodeString float str of
    Ok f ->
      updater f
    Err _ ->
      NoOp

一般に文字列から浮動小数に変換する場合は "abc" など変換できない場合が存在するため、エラーを考慮に入れる必要があります。 decodeString float では文字列を受け取って Result String Float という型の値を返します。 これは HaskellScalaにおける Either 型と同じです。

Result 型は具体的には2つのケースが値として得られます。

  • Ok Float : Float への変換が成功した。
  • Err String : 変換が失敗したためエラーメッセージを返した。 これをパターンマッチングで受け取り、成功した場合は変換に成功した値を使って UpdateHeight を、失敗した場合は NoOp (何もしない)を送ります。

Update

送信された msg の値は update 関数で処理されます。

type Msg =
  NoOp
  | UpdateHeight Float
  | UpdateWeight Float

update : Msg -> Model -> Model
update msg model =
  case msg of
    NoOp ->
      model
    UpdateHeight newHeight ->
      { model | height = newHeight }
    UpdateWeight newWeight ->
      { model | weight = newWeight }

{ model | height = newHeight }height の値だけを変更した新しいモデルを返す構文です。 そのため、この関数内で model 引数自体の値が書き換わることはありません。

また、はじめにも説明しましたが Msg 型で定義されたアクション以外はアプリケーション上発生させることができません。 そのため、 update で全てのケースに対して処理を記述できた以上は考慮漏れによるバグは発生しないのです。

debuggerの紹介

最新のElm 0.18では高機能なデバッガが利用可能になりました。コンパイル時に --debug を指定するだけで自動的に適用されます。

$ elm-make BMI.elm --debug --output debug.html

動作するサンプルはこちら

先程の図にあるような各 model の状態を時間を遡って確認することができるようになります。 詳しくは以下の公式ブログの動画を御覧ください。パないです。

the perfect bug report

まとめ

Elmの小規模なアプリケーションを見てきましたが、いかがだったでしょうか。JSで書く場合だったらもっと素早く作れると思いますが、これまで見てきたポイントで

  • BMI値や2つの入力部分の更新漏れ
  • 浮動小数に変換できない場合の考慮漏れ

などが起こりやすくなりますし、それに加えてスコープをきちんと管理しないと関数内の一時的な変数の管理が非常に煩雑になります。

AngularやReactなどのフレームワークではこの辺のモデルデータに基づくビューの更新などが容易にはなっていますが、如何せん素のJavaScriptに依存するため起こりうる状態の数が膨れ上がってしまいます。その点では Elm はとても堅牢です。

今回Elmに学ぶことは「アプリケーションの取りうる状態を定義・把握すること」「データと振る舞いとの分離」「データが不変であること」がとても堅牢なアプリケーションを作る秘訣であることです。 普段作っているアプリケーション全体をこのように管理するのは言語の違いもあって困難かもしれませんが、小さい部品を構築するときに頭に入れておくと良いでしょう。

外部連携APIのモックサーバをSwaggerを利用して作る

外部APIとの連携をしたい。でも同時並行で実装中でモックすら無い。どうしよう…。

様々な関係会社の方々と連動して仕様を定めながら開発を進めていかなければならない場合、実際の接続を確認しながら実装を作りたいけど接続先のサーバがない、という状況が起こると思います。 簡単なものであれば、 Mockable.ioなどを使ってシンプルに応答を返すこともできるのですが、実際に開発やテストを行うには幾つかの機能が求められます。

  • 特定条件のリクエストに対してエラー応答したい、またはタイムアウトを発生させたい
  • 特定条件のリクエストに対して様々なパターンの正常応答を返したい
  • 開発の進行に伴い、実装に合わせてモックの動きもバージョン管理したい

このようなニーズに答えるにはMockable.ioなどのサービスだけでは難しく、API開発元に開発中バージョンのモックを作ってもらうか、自らモックサーバを実装する必要が出てきます。

できれば開発元にモックやクライアントライブラリの作成をお願いしたいと思いつつ、オープンなAPIでなければそのようなものは作られないでしょう。 しかし、自作するにしてもスクラッチでWebアプリケーションを作って本格的にAPIサーバを作るのは辛いですよね。(そこまで辛くなければ良いのですが…) そこで、なんらかのツールを使ってAPIモックサーバを作ることを考えてみましょう。

続きを読む

ユークリッド互除法と連分数と円周率の有理数近似

ユークリッド互除法

ユークリッドの互除法と言うのはご存知でしょうか。 2つの数の最大公約数を求めるアルゴリズムですね。例えば、390と91ではこうなります。

\[\begin{aligned} 390 &= 91 \times 4 + 26 \\ 91 &= 26 \times 3 + 13 \\ 26 &= 13 \times 2 + 0 \end{aligned}\]

商と余りを計算して、除数と余りでもう一度互除法に…と順番に繰り返していくと最終的に最大公約数が13であるとわかります。

連分数表示

これらの等式の両辺を除数で割って、次のように変形してみましょう。

\[\begin{aligned} \frac{390}{91} &= 4 + \frac{26}{91} \\ \frac{91}{26} &= 3 + \frac{13}{26} \\ \frac{26}{13} &= 2 \end{aligned}\]

更にこれを逆数に。

\[\begin{aligned} \frac{91}{390} &= \frac{1}{4 + \frac{26}{91}} \\ \frac{26}{91} &= \frac{1}{3 + \frac{13}{26}} \\ \frac{13}{26} &= \frac{1}{2} \end{aligned}\]

左辺と同じものがあるので代入します。(ついでに最大公約数も分かっているので、左辺を約分します。)

\[ \frac{7}{30} = \frac{91}{390} = \frac{1}{4 + \frac{1}{3 + \frac{1}{2}}} \]

これが連分数表示です。$\frac{1}{4+}\frac{1}{3+}\frac{1}{2}$ と書いたり、$[0;4,3,2]$とすることもあります。

連分数に現れてくる数値は、ユークリッド互除法の商の順番と一致していますね。

円周率でユークリッド互除法

ユークリッド互除法を円周率$\pi$で実験してみると次のようになります。$\pi$は割り切れないのでいつまでも続きます。

\[\begin{aligned} \pi &= 1 \times 3 + (\pi - 3) \\ 1 &= (\pi - 3) \times 7 + (22 - 7\pi) \\ (\pi - 3) &= (22 - 7\pi) \times 15 + (106\pi - 333) \\ (22 - 7\pi) &= (106\pi - 333) \times 1 + (355 - 113\pi) \\ &\vdots \end{aligned}\]

これを使って先の連分数表示をすることができます。

\[ \pi = [3;7,15,1,\dots] \]

この無限連分数ですが、途中で打ち切れば当然近似値が得られます。有限の連分数は順に計算すれば必ず有理数になるので、以下のように計算できます。

\[\begin{aligned} \pi &\approx [3;7] = \frac{22}{7} = 3.1428571428\dots \\ \pi &\approx [3;7,15] = \frac{333}{106} = 3.1415094339\dots \\ \pi &\approx [3;7,15,1] = \frac{355}{113} = 3.1415929203\dots \\ & \vdots \end{aligned}\]

このようにして、小数以下6桁まで一致するシンプルな近似値$\frac{355}{113}$が得られます。

はてなブログにMathJaxを使って数式を埋め込む

MathJaxを使って次のような数式をブログに記述できます。

$$\phi = 1+\frac{1}{1+}\frac{1}{1+}\ldots$$

インストール

Using the MathJax CDNに書かれている内容と同じです。

[設定] > [詳細設定タブ] > [headに要素を追加] に以下を追加します。

<script type="text/javascript"
  src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

これによって、MathJaxがロードされ数式を表示可能になります。

記事を書く

ここからは基本的に LaTeX の記法を使います。 上記の数式であればこうなります。

$$\phi = 1+\frac{1}{1+}\frac{1}{1+}\ldots$$

特別な記法でラップする必要もなく、こんな感じでそのまま記事に書くだけです。