Fp-ts: Array of Options to Option of Array?

Created on 20 Feb 2020  路  4Comments  路  Source: gcanti/fp-ts

馃摉 Documentation

I am quite confused with sequence/traverse behaviour, and I'd need some assistance.
I'd like to convert an Array of Options to an Option of Array. I was sure sequence/traverse is a way:

import { sequenceT } from './Apply';
import { some, option, none } from './Option'

const sequenceTOption = sequenceT(option)

arrayOfOptions = [some(1), none]

// Argument of type 'Option<number>[]' is not assignable to parameter of type 'Option<number>[] & { 0: Option<any>; }'.
// Property '0' is missing in type 'Option<number>[]' but required in type '{ 0: Option<any>; }'.ts(2345)
// Apply.ts(129, 15): '0' is declared here.
sequenceTOption(...arrayOfOptions)

How can one do that? I was looking for an implementation of sequence (sequenceA?) for Array e.g. inApply.ts but couldn't find one.

Your environment

| Software | Version(s) |
| ---------- | ---------- |
| fp-ts | 2.5.0 |
| TypeScript | 3.7.2 |

Most helpful comment

@vicrac sequence and sequenceT (sequenceS) are pretty different:

  • sequence comes from Traversable and works with (homogeneous) arrays
  • sequenceT (sequenceS) comes from Apply and works with non empty tuples (non empty structs) i.e the types can be different

So with sequenceT (sequenceS) you can do:

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

// Option<number> -----v         v---- Option<string>
sequenceT(O.option)(O.some(1), O.some('a'))

//      Option<number> -----v             v---- Option<string>
sequenceS(O.option)({ a: O.some(1), b: O.some('a') })

however with sequence you can't do this:

import * as O from 'fp-ts/lib/Option'
import * as A from 'fp-ts/lib/Array'

//                                        v--- error: Type 'string' is not assignable to type 'number'
A.array.sequence(O.option)([O.some(1), O.some('a')])
// this is ok since they are all `Option<number>`s
A.array.sequence(O.option)([O.some(1), O.some(2)]) 

When using sequenceT (sequenceS) we need at least one element because Apply doesn't have the of operation, so we can't lift [] ({}).

All 4 comments

sequenceT requires a non-empty list of args, so in your example this will work:

sequenceTOption(some(1), none);

but your version will not, since TS infers just Array<Option<number>> for arrayOfOptions, which can be empty.

Otherwise, I think you are looking for:

import { array } from 'fp-ts/lib/Array'

array.sequence(option)(arrayOfOptions) // Option<number[]>

@giogonzo thanks, indeed this works fine for me, but I am wondering, is it by design? Wouldn't it be better to have a, say sequenceA in Apply, following the convention? @gcanti what do you think?

Also, I am thinking of this requirement for sequence to be passed a NonEmptyArray - is it strictly necessary? E.g. Promise.all (which actualy a non standard implementation of sequence) is behaving correctly for an empty array of promises (it returns a promise immediately resolving to an empty array).

@vicrac sequence and sequenceT (sequenceS) are pretty different:

  • sequence comes from Traversable and works with (homogeneous) arrays
  • sequenceT (sequenceS) comes from Apply and works with non empty tuples (non empty structs) i.e the types can be different

So with sequenceT (sequenceS) you can do:

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

// Option<number> -----v         v---- Option<string>
sequenceT(O.option)(O.some(1), O.some('a'))

//      Option<number> -----v             v---- Option<string>
sequenceS(O.option)({ a: O.some(1), b: O.some('a') })

however with sequence you can't do this:

import * as O from 'fp-ts/lib/Option'
import * as A from 'fp-ts/lib/Array'

//                                        v--- error: Type 'string' is not assignable to type 'number'
A.array.sequence(O.option)([O.some(1), O.some('a')])
// this is ok since they are all `Option<number>`s
A.array.sequence(O.option)([O.some(1), O.some(2)]) 

When using sequenceT (sequenceS) we need at least one element because Apply doesn't have the of operation, so we can't lift [] ({}).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mohsensaremi picture mohsensaremi  路  3Comments

bioball picture bioball  路  4Comments

mmkal picture mmkal  路  3Comments

jollytoad picture jollytoad  路  4Comments

FruitieX picture FruitieX  路  3Comments