JavaScript + 関数型プログラミングメモ

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.OkResult.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(),
  );
}
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.