JavaScript + 関数型プログラミングメモ
- JavaScriptでMaybe
- JavaScriptでEither: ←いまここ
folktale v2においては Either は Result
という名前になっている。Leftは、 Result.Error
, Right は Result.Ok
という名前になっている。まずは Either を作る。
const assert = require('assert');
const Result = require('folktale/result');
// create either
{
const rights = [
Result.Ok(1),
Result.Ok({ one: 1 }),
];
rights.forEach((d) => {
assert(d instanceof Result.Ok);
});
const lefts = [
Result.Error(1),
Result.Error({ one: 1 }),
];
lefts.forEach((d) => {
assert(d instanceof Result.Error);
});
}
例外throw型の関数は、 Result.try()
を使って関数の返り値or送出された例外をEitherにすることができる。Eitherは mapとmapErrorで、それぞれの成功状態を変更せずに、値を変更できる。matchWith でパターンマッチング、条件分岐ができる。mergeを使うと、成功状態を問わず値を取り出すことが出来る。Eitherが Result.Ok
か Result.Error
かは、hasInstanceOf
で判別することができる。
// work with either
{
const f = (arg) => {
if (arg) return arg;
throw Error('falsy');
};
assert.deepEqual(
Result.Ok('HELLO!'),
Result.try(() => f('hello'))
.map(str => str.toUpperCase()).map(str => str.concat('!')),
);
assert.deepEqual(
Result.Error(Error('falsy')),
Result.try(f)
.map(str => str.toUpperCase()).map(str => str.concat('!')),
);
assert(Result.Ok.hasInstance(Result.Ok('hello')));
assert(Result.Error.hasInstance(Result.Error('hello')));
const getName = (id) => {
if (id === 1) return 'alice';
throw Error('no such user!');
};
Result.try(() => getName(1)).matchWith({
Ok: ({ value }) => { assert.equal('alice', value); },
Error: () => { throw Error('cannot reach here'); },
});
Result.try(() => getName(2)).matchWith({
Ok: () => { throw Error('cannot reach here'); },
Error: ({ value }) => { assert.deepEqual(Error('no such user!'), value); },
});
assert.equal(
'guest',
Result.try(() => getName()).mapError(() => 'guest').merge(),
);
assert.equal(
'alice',
Result.try(() => getName(1)).mapError(() => 'guest').merge(),
);
}