TypeScriptで作成した State Monadをモジュールにしてみた。
importの指定に、若干迷いましたので共有します。
今回の目標
TypeScriptのモジュール化を行う。
モジュールの配置
State Monadモジュールは、ファイル名stateMonad.ts
とし、root/monad/state/stateMonad.ts
に配置する。
Stackモジュールは、ファイル名stack.ts
とし、root/stack/stack.ts
に配置する。
テストモジュールは、ファイル名stackTest.ts
とし、root/stackTest.ts
に配置する。
State Monadモジュール
export
module monad.state {
export
interface Tuple2<A,B> {
fst: A
snd: B
}
export
class State<T,X>{
runState: (t:T) => Tuple2<X,T>
evalState = (t:T):X => this.runState(t).fst
execState = (t:T):T => this.runState(t).snd
constructor(g:(t:T) => Tuple2<X,T>){
this.runState = g
}
static returns<T,X>(v:X):State<T,X>{
return new State<T,X>((t:T) => { return {fst:v, snd:t } })
}
bind<B>(f: (x:X) => State<T,B>):State<T,B>{
var g = (t:T) => {
var st = this.runState(t)
return f(st.fst).runState(st.snd)
}
return new State<T,B>(g)
}
}
export
class MonadState {
static get<T>():State<T,T> {
var g = (t:T) => {
return { fst: t, snd: t }
}
return new State<T,T>(g)
}
static put<T>(a:T):State<T,void> {
var g = (t:T) => {
return { fst: null, snd: a }
}
return new State<T,void>(g)
}
}
}
モジュールとして外部に提供するmodule
、class
にはexport
を付加した。
Tuple2
は本来なら別モジュールとするべきだが、今回はこのモジュールに含めた。
Stackモジュール
import ms = require("../monad/state/stateMonad")
export
module stack {
export
class Stack<X> {
pop = <X>():ms.monad.state.State<X,X[]> =>
ms.monad.state.MonadState.get<X[]>()
.bind((e:X[]) => {
return ms.monad.state.MonadState.put<X[]>(e.slice(1))
.bind(k => ms.monad.state.State.returns(e[0])) })
push = <X>(i:X):ms.monad.state.State<X,void> =>
ms.monad.state.MonadState.get<X[]>()
.bind((e:X[]) =>
ms.monad.state.MonadState.put<X[]>([i].concat(e)))
}
}
外部モジュールのstateMonad.ts
を使用するため、import
が必要。
require
はこのモジュールからの相対パスを指定する。
また、外部モジュールを使用する際は、import
に使用したms.
にフォルダ名monad.state.
を付加して使用する。
テストモジュール
import ms = require("./monad/state/stateMonad")
import st = require("./stack/stack")
var fnc = <X>(st:st.stack.Stack):ms.monad.state.State<X,X[]> =>
st.pop()
.bind(e => st.pop())
.bind(e => st.push(20))
.bind(e => st.pop())
.bind(e => st.push(e*5))
console.log(fnc(new st.stack.Stack<number>()).execState([1,2,3])) //=> [100,3]
外部モジュールのstateMonad.ts
、stack.ts
のimport
が必要。
ここでも相対パスを指定する。
コンパイル
コンパイルする際は、--module commonjs
のオプションを付加する。
Webで見ると--module amd
でも良いと書いてあるが、私の環境では実行時にエラーとなった。
rootに移動し、コンパイルコマンドを発行する。
ts stateTest.ts --module commonjs
実行
rootに移動し、node.jsにて実行する。
node stateTest.js // [100,3]
期待した値が表示された。
まとめ
以前import
に指定していたmodule
がdeprecatedになっているため、require
を使用する。
require
には相対パスを指定する(別の方法があるかもしれません)。
外部クラスを使用する場合は、import
に使用した変数(今回の場合はms
)と、フォルダ階層を.
で区切り指定する。
コンパイル時には、--module commonjs
のオプションを付加する。