Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: How to "yield" more than one Option? #1236

Closed
bobaaaaa opened this issue Jun 10, 2020 · 5 comments
Closed

Question: How to "yield" more than one Option? #1236

bobaaaaa opened this issue Jun 10, 2020 · 5 comments

Comments

@bobaaaaa
Copy link

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
@DenisFrezzato
Copy link
Collaborator

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]>

@gcanti
Copy link
Owner

gcanti commented Jun 10, 2020

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)
    )
  )
)

@gcanti
Copy link
Owner

gcanti commented Jun 10, 2020

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)

@bobaaaaa
Copy link
Author

Nice. Thank you all ❤️ . I close the issue.

@fneco
Copy link

fneco commented May 3, 2021

Thank you for helpful issue and answers.
I'd like to add another option since 2.8.0 for next visitor.

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

pipe(
  O.bindTo('foo')(O.some('foo')),
  O.bind('bar', () => O.some('bar')),
  O.map(({ foo, bar }) => f(foo, bar))
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants