Rodhos Soft

備忘録を兼ねた技術的なメモです。Rofhos SoftではiOSアプリ開発を中心としてAndroid, Webサービス等の開発を承っております。まずはご相談下さい。

状態モナドを作ってみる

typescriptで状態モナドを作ってみます。

状態モナド

 S \to (R,S)
という状態を受け取って結果と変化した状態を返す関数です。

これを

export type State<R,S> = (s:S) => {result:R,state:S}

と定義しておきます。

初期値を作る関数を

export const unit = <R,S>(result:R) => (state:S) => { return {result:result, state:state}}; 

と定義します。これで

    const m0 = unit<number,number>(100);

のように初期入力値を作ることができます。

次に数を2倍する関数を作りましょう。そして関数が呼ばれる回数を状態としてカウントすることを考えます。
具体的には

    const f = (r:number) => (s:number) => { return {result:r*2, state:s+1}}

のような関数を用意します。つまり、状態を受け取ったら値を2倍しつつ状態を更新して返すという関数です。
これは

    const f: (number) =>State<number, number>

という型を持っていることに注意しましょう。

作っておいた状態モナドm0にこの関数を適用するための関数としてbindを用意します。

export const bind = <R,S,Q>(m:State<R,S>, f:(r:R)=>State<Q,S>) => (s:S) => {
    const next = m(s);
    return f(next.result)(next.state);
}

これは新しく状態モナドを作って、その状態モナドでは、元の状態モナドを先に使って結果を求め、それにfを適用するようにしてあります。

bindを使って、m0にfを3回くらい適用させてみましょう。

    const m0 = unit<number,number>(100);
    const m1 = bind(m0,f);
    const m2 = bind(m1,f);
    const m3 = bind(m2,f);

m1,m2を用いたのはわかりやすさのためで、bindを連続して作用させても構いません。

できた結果の状態モナドm3を使うには初期状態を設定する必要があります。

    const ans = m3(0)

ans.result == 800
ans.state == 3
となり、きちんとカウントしていることがわかると思います。

状態モナドの説明はこれで終わりです。
色々な使い方がありそうだということがわかると思います。

以上をまとめたコードがこちらになります。

export type State<R,S> = (s:S) => {result:R,state:S}

export const unit = <R,S>(result:R) => (state:S) => { return {result:result, state:state}}; 
export const bind = <R,S,Q>(m:State<R,S>, f:(r:R)=>State<Q,S>) => (s:S) => {
    const next = m(s);
    return f(next.result)(next.state);
}

export function stateTest() {
    /// double number , state: count of operation
    const f = (r:number) => (s:number) => { return {result:r*2, state:s+1}}

    const m0 = unit<number,number>(100);
    const m1 = bind(m0,f);
    const m2 = bind(m1,f);
    const m3 = bind(m2,f);
    
    const display = <R>(m:State<R,number>) => {
        console.log("result:"+m(0).result + " state:"+m(0).state);
    }

    display(m0);
    display(m1);
    display(m2);
    display(m3);

    /*
        result:100 state:0
        result:200 state:1
        result:400 state:2
        result:800 state:3
    */

    
}

stateTest();

ありがとうございました。

ローカルHTMLのメモ

WKWebViewで実装すると
フォルダ参照ならhtml内のlinkは./でプロジェクト直下になっているようだ。

WKWebViewは今の所、コード上で貼り付けるしかない。

WKNavigationDelegateでnavigationResponseでdocument.locationの移動を検知できる。
decisionHandler(.allow)で許可する。

challenge: URLAuthenticationChallengeで
信頼するかどうか

        print("[Warning]challenge AuthenticationChallange")
        let cred = URLCredential(trust: challenge.protectionSpace.serverTrust!);
        completionHandler(.useCredential, cred)

Build Phaseでプロジェクト直下のファイルをResourceにコピーできる。
ResourceにコピーできればMainBundleから取得できる。

cmakeの仕方

以下を参考にする。
qiita.com

コマンドラインのビルド

main.cpp, hello.hppがあるとする。
これらをまず

g++ -c main.cpp hello.hpp

コンパイルして.oファイルを作る。
そしてリンクする。

g++ -o a.out main.o hello.o

cmake

CMakeLists.txtを作る

cmake_minimum_required(VERSION 2.8)
project(sample_project CXX)

add_executable(a.out main.cpp hello.cpp)

buildフォルダを作り、そこで実行する。

mkdir build
cd build
cmake ..
make