Fp-ts: Question: How to "yield" more than one Option?

Created on 10 Jun 2020  路  4Comments  路  Source: gcanti/fp-ts

Problem

I have two Options and I want to do an operation only if both are some. I found this issue #322 but failed to get it working 馃槩 .

Example in typescript

import { some } from 'fp-ts/lib/Option';
import { pipe } from 'fp-ts/lib/pipeable';

const foo: Option<string> = some('foo');
const bar: Option<string> = some('foo');

// ??
pipe([foo, bar], ???);

Example in scala

for (
  foo <- Some("foo");
  bar <- Some("bar")
) yield foo + bar

Most helpful comment

A few options

Option 1 (liftA2)

import * as O from 'fp-ts/lib/Option'
import { pipe } from 'fp-ts/lib/function'

const concat = (a: string) => (b: string) => a + b

pipe(O.some(concat), O.ap(O.some('foo')), O.ap(O.some('bar')))

Option 2 (sequenceT)

import * as O from 'fp-ts/lib/Option'
import * as A from 'fp-ts/lib/Apply'
import { pipe } from 'fp-ts/lib/function'

pipe(
  A.sequenceT(O.option)(O.some('foo'), O.some('bar')),
  O.map(([foo, bar]) => foo + bar)
)

Option 3 (sequenceS)

import * as O from 'fp-ts/lib/Option'
import * as A from 'fp-ts/lib/Apply'
import { pipe } from 'fp-ts/lib/function'

pipe(
  A.sequenceS(O.option)({ foo: O.some('foo'), bar: O.some('bar') }),
  O.map(({ foo, bar }) => foo + bar)
)

Option 4 (chain + map)

import * as O from 'fp-ts/lib/Option'
import { pipe } from 'fp-ts/lib/function'

pipe(
  O.some('foo'),
  O.chain((foo) =>
    pipe(
      O.some('bar'),
      O.map((bar) => foo + bar)
    )
  )
)

All 4 comments

What you're looking for is sequenceT.

import * as O from 'fp-ts/lib/Option'
import { pipe } from 'fp-ts/lib/pipeable'
import { sequenceT } from 'fp-ts/lib/Apply'

const foo: O.Option<string> = O.some('foo');
const bar: O.Option<string> = O.some('foo');

sequenceT(O.option)([foo, bar]) // Option<[string, string]>

A few options

Option 1 (liftA2)

import * as O from 'fp-ts/lib/Option'
import { pipe } from 'fp-ts/lib/function'

const concat = (a: string) => (b: string) => a + b

pipe(O.some(concat), O.ap(O.some('foo')), O.ap(O.some('bar')))

Option 2 (sequenceT)

import * as O from 'fp-ts/lib/Option'
import * as A from 'fp-ts/lib/Apply'
import { pipe } from 'fp-ts/lib/function'

pipe(
  A.sequenceT(O.option)(O.some('foo'), O.some('bar')),
  O.map(([foo, bar]) => foo + bar)
)

Option 3 (sequenceS)

import * as O from 'fp-ts/lib/Option'
import * as A from 'fp-ts/lib/Apply'
import { pipe } from 'fp-ts/lib/function'

pipe(
  A.sequenceS(O.option)({ foo: O.some('foo'), bar: O.some('bar') }),
  O.map(({ foo, bar }) => foo + bar)
)

Option 4 (chain + map)

import * as O from 'fp-ts/lib/Option'
import { pipe } from 'fp-ts/lib/function'

pipe(
  O.some('foo'),
  O.chain((foo) =>
    pipe(
      O.some('bar'),
      O.map((bar) => foo + bar)
    )
  )
)

Another option you may like, though it's not contained in fp-ts's core (yet): in fp-ts-contrib there's a simulation of Haskell do notation

import * as O from 'fp-ts/lib/Option'
import { Do } from 'fp-ts-contrib/lib/Do'

Do(O.option)
  .bind('foo', O.some('foo'))
  .bind('bar', O.some('bar'))
  .return(({ foo, bar }) => foo + bar)

Nice. Thank you all 鉂わ笍 . I close the issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mohsensaremi picture mohsensaremi  路  3Comments

steida picture steida  路  4Comments

mmkal picture mmkal  路  3Comments

bioball picture bioball  路  4Comments

steida picture steida  路  4Comments