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.
| Software | Version(s) |
| ---------- | ---------- |
| fp-ts | 2.5.0 |
| TypeScript | 3.7.2 |
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) arrayssequenceT (sequenceS) comes from Apply and works with non empty tuples (non empty structs) i.e the types can be differentSo 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 [] ({}).
Most helpful comment
@vicrac
sequenceandsequenceT(sequenceS) are pretty different:sequencecomes fromTraversableand works with (homogeneous) arrayssequenceT(sequenceS) comes fromApplyand works with non empty tuples (non empty structs) i.e the types can be differentSo with
sequenceT(sequenceS) you can do:however with
sequenceyou can't do this:When using
sequenceT(sequenceS) we need at least one element becauseApplydoesn't have theofoperation, so we can't lift[]({}).