GithubHelp home page GithubHelp logo

gcanti / fp-ts-contrib Goto Github PK

View Code? Open in Web Editor NEW
199.0 199.0 33.0 725 KB

A community driven utility package for fp-ts

Home Page: https://gcanti.github.io/fp-ts-contrib/

License: MIT License

TypeScript 99.84% JavaScript 0.16%

fp-ts-contrib's People

Contributors

bwlt avatar denisfrezzato avatar gabro avatar gcanti avatar gillchristian avatar giogonzo avatar imax153 avatar kgtkr avatar lucas-t5 avatar malteneuss avatar pbadenski avatar pfgray avatar raine avatar sledorze avatar srachamim avatar thewilkybarkid avatar waynevanson avatar wraul avatar ybogomolov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fp-ts-contrib's Issues

'Do' does not properly infer Kind<F, void> (HKT with void as return type)

πŸ› Bug report

Please refer to #37.

Current Behavior

The following code works:

interface Console<F extends URIS> {
  putStrLn: (message: string) => Kind<F, void>
  getStrLn: Kind<F, string>
}
// ask something and get the answer
const ask = (question: string): Kind<F, string> =>
  Do(F)
    .do(F.putStrLn(question) as Kind<F, unknown>)
    .bind('answer', F.getStrLn)
    .return(({ answer }) => answer)

When I remove as Kind<F, unknown> from the code, it emits this error:

Argument of type 'Kind<F, void>' is not assignable to parameter of type 'Kind<F, unknown>'.
  Type 'URItoKind<void>[F]' is not assignable to type 'URItoKind<unknown>[F]'.
    Type 'URItoKind<void>' is not assignable to type 'URItoKind<unknown>'.
      Types of property 'Eq' are incompatible.
        Type 'Eq<void>' is not assignable to type 'Eq<unknown>'.
          Type 'unknown' is not assignable to type 'void'.
            Type 'URItoKind<void>[F]' is not assignable to type '(Eq<unknown> & Ord<unknown> & None & IO<unknown> & Task<unknown>) | (Eq<unknown> & Ord<unknown> & Some<unknown> & IO<unknown> & Task<unknown>)'.
              Type 'IO<void> | Task<void> | None | Eq<void> | Ord<void> | Some<void>' is not assignable to type '(Eq<unknown> & Ord<unknown> & None & IO<unknown> & Task<unknown>) | (Eq<unknown> & Ord<unknown> & Some<unknown> & IO<unknown> & Task<unknown>)'.
                Type 'IO<void>' is not assignable to type '(Eq<unknown> & Ord<unknown> & None & IO<unknown> & Task<unknown>) | (Eq<unknown> & Ord<unknown> & Some<unknown> & IO<unknown> & Task<unknown>)'.
                  Type 'IO<void>' is not assignable to type 'Eq<unknown> & Ord<unknown> & None & IO<unknown> & Task<unknown>'.
                    Type 'IO<void>' is not assignable to type 'Eq<unknown>'.
                      Type 'URItoKind<void>[F]' is not assignable to type 'Eq<unknown> & Ord<unknown> & Some<unknown> & IO<unknown> & Task<unknown>'.
                        Type 'IO<void> | Task<void> | None | Eq<void> | Ord<void> | Some<void>' is not assignable to type 'Eq<unknown> & Ord<unknown> & Some<unknown> & IO<unknown> & Task<unknown>'.
                          Type 'IO<void>' is not assignable to type 'Eq<unknown> & Ord<unknown> & Some<unknown> & IO<unknown> & Task<unknown>'.
                            Property 'equals' is missing in type 'IO<void>' but required in type 'Eq<unknown>'.
                              Type 'URItoKind<void>[F]' is not assignable to type 'Eq<unknown>'.
                                Type 'IO<void> | Task<void> | None | Eq<void> | Ord<void> | Some<void>' is not assignable to type 'Eq<unknown>'.
                                  Property 'equals' is missing in type 'IO<void>' but required in type 'Eq<unknown>'.ts(2345)
Eq.d.ts(32, 14): 'equals' is declared here.
Eq.d.ts(32, 14): 'equals' is declared here.

This happens when the HKT's return type is void (Kind<F, void>)

Expected behavior

This should work (without as Kind<F, unknown>)

// ask something and get the answer
const ask = (question: string): Kind<F, string> =>
  Do(F)
    .do(F.putStrLn(question))
    .bind('answer', F.getStrLn)
    .return(({ answer }) => answer)

Reproducible example

Please refer to #37.

Suggested solution(s)

No idea

Additional context

tsconfig.json

  "compilerOptions": {
    /* Basic Options */
    "target": "es2020",
    "module": "CommonJS",
    "outDir": "./dist",
    /* Strict Type-Checking Options */
    "strict": true,
    /* Module Resolution Options */
    "moduleResolution": "Node",
    /* Experimental Options */
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipLibCheck": true,
  },

Your environment

Which versions of fp-ts-contrib are affected by this issue? Did this work in previous versions of fp-ts-contrib?

Software Version(s)
fp-ts 2.3.1
fp-ts-contrib 0.1.8
TypeScript 3.7.4

Using Free in multiple files

Do you want to request a feature or report a bug?

I'm not sure whether it qualifies as a bug, it may be my lack of understanding.

What is the current behaviour?

Reviewing the example code at the test directory of this project I have attempted to use Free. According to the test code the file where the monad Expr is defined needs to contain the following bit of code (or so it seems):

type ExprF<A> = Add<A> | Lit<A>

declare module 'fp-ts/lib/HKT' {
  interface URItoKind<A> {
    Expr: ExprF<A>
  }
}

Without it, the compiler displays an error No overload matches this call. This works well when only one file in the project defines an ExprF but when there is more than one occurrence they step on each other. So, for instance having two files on the same project:

// addLit.ts
type ExprF<A> = Add<A> | Lit<A>

declare module 'fp-ts/lib/HKT' {
  interface URItoKind<A> {
    Expr: ExprF<A>
  }
}

and

// fooBar.ts
type ExprF<A> = Foo<A> | Bar<A>

declare module 'fp-ts/lib/HKT' {
  interface URItoKind<A> {
    Expr: ExprF<A>
  }
}

I get an error Subsequent property declarations must have the same type. Property 'Expr' must be of type 'Expr<A>', but here has type 'Exp<A>'

If the current behaviour is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://codesandbox.io/ or similar.

Create a different Free Expr on two files in the same package as described above.

What is the expected behavior?

Be able to have different Expr in the same project.

Which versions of fp-ts-contrib, and which browser and OS are affected by this issue? Did this work in previous versions of fp-ts-contrib?

0.1.6 ~ NixOs 19.09 ~ I don't know

Do supports destructuring binding

πŸš€ Feature request

Related #35

Do does not support destructuring binding.

do
  (a, b) <- m
  let (a, b) = x
  ...

Suggested Solution

.bindD(m.map(x => ({ a: x.a, b: x.b }))) === .bind("tmp", m).letL("a" ,({ tmp }) => tmp.a).letL("b" ,({ tmp }) => tmp.b)
.bindDL(() => m.map(x => ({ a: x.a, b: x.b }))) === .bindL("tmp", () => m).letL("a" ,({ tmp }) => tmp.a).letL("b" ,({ tmp }) => tmp.b)
.letD({ a: 1, b: 2 }) === .sequenceS({ a: M.of(1), b: M.of(2) })
.letDL(() => ({ a: 1, b: 2 })) === .sequenceSL(() => ({ a: M.of(1), b: M.of(2) }))

Expose modules without lib/es6 prefix

πŸš€ Feature request

Current Behavior

As a fp-ts-contrib user, I will need to import modules like fp-ts-contrib/lib/Do or fp-ts-contrib/es6/Do.

Desired Behavior

Ideally, it would be great to just import the module directly without prefix like fp-ts-contrib/Do that fp-ts already shipped in 2.8.0.

Suggested Solution

Maybe we can follow what fp-ts has done in gcanti/fp-ts#1241 to fix this.

Who does this impact? Who is this for?

fp-ts-contrib users

Describe alternatives you've considered

Additional context

Your environment

Software Version(s)
fp-ts 2.8.0
fp-ts-contrib 0.5.1
TypeScript 3.9.2

When having multiple 'fp-ts' libraries initialized - fp-ts-copntrib behaves in a weird way

πŸ› Bug report

Current Behavior

I have a separate 'common' npm package that has 'fp-ts' dependency. I use that 'common' package in my main application, which has also a dependency to 'fp-ts' as long as dependency to 'fp-ts-contrib'.

The issue I have is that in this setup Do notation behaves in a weird way. I get some errors that do not make sense (The screenshot is attached).

image

image

Expected behavior

I would expect it to be working the same even if fp-ts is initialized in underneath dependencies themselves.

Reproducible example

Suggested solution(s)

Additional context

Your environment

Software Version(s)
fp-ts 2.10.5
fp-ts-contrib 0.1.26
TypeScript 4.2.3

`Zipper` should have `toReadonlyArray`

πŸš€ Feature request

As any other data-structure in the fp-ts library, I expect Zipper to support ReadonlyArray. This is important because most people that use Zipper will want to work with immutable data-structures.

Current Behavior

Zipper has toArray. Doesn't have toReadonlyArray.

Desired Behavior

Zipper should have a toReadonlyArray of type: <A>(z: Zipper<A>) => ReadonlyArray<A>.

Suggested Solution

Just alias the new function to toArray.

export const toReadonlyArray: <A>(fa: Zipper<A>) => ReadonlyArray<A> = toArray

PR #76 does exactly that.

Who does this impact? Who is this for?

It's not a breaking change, so it shouldn't impact anyone. It's for people who cares about immutability.

Describe alternatives you've considered

The alternative is to use fromArray from fp-ts/ReadonlyArray after each toArray from fp-ts-contrib/Zipper:

import * as A from 'fp-ts/ReadonlyArray'
import * as Z from 'fp-ts-contrib/Zipper'

const as = pipe(
 Z.of('a'),
 Z.toArray,
 A.fromArray,
)

This is what I currently do, but it's not nice and not clean.

Additional context

Generally I think it's better to have the implementation of Zipper uses ReadonlyArray.

Your environment

Software Version(s)
fp-ts 2.10.4
fp-ts-contrib 0.1.21
TypeScript 4.2

AsyncIterable Module

πŸš€ Feature request

fo-ts bindings for AsyncIterable module, which is lazy lists from the promise land.

Current Behavior

Desired Behavior

Suggested Solution

Who does this impact? Who is this for?

Describe alternatives you've considered

Haven't considered if we should DIY with a mix like Iterable<Task<A>>, which might be the preferred solution.
I feel like AsyncIterable exists because Promises are eager.

Additional context

Your environment

Software Version(s)
fp-ts
fp-ts-contrib
TypeScript

regex test is not pure

regex.test on global or sticky regular expressions will mutate the lastIndex, therefore using test is not a pure function.

For example this is what sanctuary is doing and this

I suspect we should do something similar here too for example this is what I have:

/**
 * Remembers `lastIndex` of the provided `regex` and resets it back after running the thunk
 */
export function withRegex<T>(regex: RegExp, thunk: () => T): T {
  const lastIndex = regex.lastIndex;
  const result = thunk();
  regex.lastIndex = lastIndex;
  return result;
}
/**
 * A pure function version of regex.test(s). i.e. this will not change the `lastIndex` prop of the regex.
 * see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test#using_test_on_a_regex_with_the_global_flag
 */
export function regexTest(regex: RegExp, s: string) {
  return withRegex(regex, function () {
    return regex.test(s);
  });
}

Do with filter (if)

πŸš€ Feature request

In Scala, you can do a for-comprehension with a if:

for {
  n <- Some(12)
  if n < 10
  m <- Some(n * 2)
} yield m

Would it be possible to do this with a Do?
Maybe with this syntax:

Do(option)
  .bind('n', some(12))
  .filter(({ n }) => n < 10)
  .bindL('m', ({ n }) => some(n * 2))
  .return(({ m }) => m)

In Scala, the for-comprehension checks that the given Monad has a withFilter method.

  • You can't do this for an Either
  • For a Future, the failed value is:
    Future(Failure(NoSuchElementException("Future.filter predicate is not satisfied")))
    But I have no idea how this could be done with a Task or a TaskEither. Maybe with a TaskOption?
  • Other Monads?

Implementing Existential Wrapper

I'm trying to write a small library to make it easier to create types that are existentially quantified. I'm using the idea of a type interface F<A> { foo : a, ext : exists E. E } (pseudocode) can be implemented as interface Fe<A,E> { foo : a, ext : E } and type F<A> = <R>(cont : <E>(x : Fe<A,E>) => R) => R. My current implementation can be found here: https://github.com/theNerd247/tsfreeapp/blob/master/existential.ts

liftExt compiles just fine. However mapExt which is supposed to make lifting functions that modify the underlying containers of existentially quantified types easier. However I get the following compiler error and I'm not sure where to start on fixing this any ideas?

existential.ts:34:3 - error TS2322: Type 'Existential2<"Either", unknown>' is not assignable to type 'Existential<F>'.
  Types of property 'runExt' are incompatible.
    Type '<R>(cont: <E>(t: Either<unknown, E>) => R) => R' is not assignable to type '<R>(cont: <E>(t: Kind<F, E>) => R) => R'.
      Types of parameters 'cont' and 'cont' are incompatible.
        Types of parameters 't' and 't' are incompatible.
          Type 'Either<unknown, E>' is not assignable to type 'Kind<F, unknown>'.
            Type 'Left<unknown>' is not assignable to type 'Kind<F, unknown>'.

34   return liftExt(x.runExt(f))
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~

existential.ts:34:27 - error TS2345: Argument of type '<E>(a: Kind<F, E>) => Kind<F, E>' is not assignable to parameter of type '<E>(t: Kind<F, E>) => Kind<F, unknown>'.
  Type 'Kind<F, E>' is not assignable to type 'Kind<F, unknown>'.
    Type 'URItoKind<E>[F]' is not assignable to type 'URItoKind<unknown>[F]'.
      Type 'URItoKind<E>' is not assignable to type 'URItoKind<unknown>'.
        Types of property 'Eq' are incompatible.
          Type 'Eq<E>' is not assignable to type 'Eq<unknown>'.
            Type 'unknown' is not assignable to type 'E'.
              Type 'URItoKind<E>[F]' is not assignable to type '(Eq<unknown> & Ord<unknown> & None) | (Eq<unknown> & Ord<unknown> & Some<unknown>)'.
                Type 'None | Eq<E> | Ord<E> | Some<E>' is not assignable to type '(Eq<unknown> & Ord<unknown> & None) | (Eq<unknown> & Ord<unknown> & Some<unknown>)'.
                  Type 'None' is not assignable to type '(Eq<unknown> & Ord<unknown> & None) | (Eq<unknown> & Ord<unknown> & Some<unknown>)'.
                    Type 'None' is not assignable to type 'Eq<unknown> & Ord<unknown> & None'.
                      Type 'None' is not assignable to type 'Eq<unknown>'.
                        Type 'URItoKind<E>[F]' is not assignable to type 'Eq<unknown> & Ord<unknown> & Some<unknown>'.
                          Type 'None | Eq<E> | Ord<E> | Some<E>' is not assignable to type 'Eq<unknown> & Ord<unknown> & Some<unknown>'.
                            Type 'None' is not assignable to type 'Eq<unknown> & Ord<unknown> & Some<unknown>'.
                              Property 'equals' is missing in type 'None' but required in type 'Eq<unknown>'.
                                Type 'URItoKind<E>[F]' is not assignable to type 'Eq<unknown>'.
                                  Type 'None | Eq<E> | Ord<E> | Some<E>' is not assignable to type 'Eq<unknown>'.
                                    Property 'equals' is missing in type 'None' but required in type 'Eq<unknown>'.

34   return liftExt(x.runExt(f))

using `Do(E.either)` results in "deprecated" warning

πŸ› Bug report

Current Behavior

Using the Either type with the Do notation is marked as deprecated with the message "Use small, specific instances instead."

Do(E.either) // <-- `either` is marked deprecated
  .bind("name", value)
  .return(({name}) => ({out: name}));

Expected behavior

It has no compiler warnings or errors.

Reproducible example

See above

Suggested solution(s)

Should either really be deprecated, or is there an alternate "smaller" type that we can use in these places?

Additional context

n/a

Your environment

Which versions of fp-ts-contrib are affected by this issue? Did this work in previous versions of fp-ts-contrib?

Software Version(s)
fp-ts 2.5.3
fp-ts-contrib 0.1.26
TypeScript 3.9.6 (build) and 4.3.2 (editor)

Iterable Module

πŸš€ Feature request

fp-ts bindings for the inbuilt Iterable<A> type, which is basically lazy lists.

Current Behavior

Desired Behavior

Suggested Solution

Who does this impact? Who is this for?

Describe alternatives you've considered

Additional context

Your environment

Software Version(s)
fp-ts
fp-ts-contrib
TypeScript

Extend TaskOption from Alt1 to Alternative1

πŸš€ Feature request

Current Behavior

Currently TaskOption implements Alt1.

Desired Behavior

Add zero to TaskOption to implement Alternative1.

Suggested Solution

const zero = getOptionM(..).none

Who does this impact? Who is this for?

People using Applicative interface.

Your environment

Software Version(s)
fp-ts 2.0.1
fp-ts-contrib 0.1.14
TypeScript 3.6

Modules / Do.ts / Example: fp-ts-to-the-max-II.ts

πŸ“– Documentation

  • I rewrote fp-ts-to-the-max-II.ts using Do.
  • I think this will help people who are just beginning to use Do.
  • It covers Do's bind, bindL, do, doL, sequenceS, return methods.
import { URIS, Kind } from 'fp-ts/lib/HKT'
import { createInterface } from 'readline'
import { flow, constVoid } from 'fp-ts/lib/function'
import * as C from 'fp-ts/lib/Console'
import * as M from 'fp-ts/lib/Monad'
import * as O from 'fp-ts/lib/Option'
import * as R from 'fp-ts/lib/Random'
import * as T from 'fp-ts/lib/Task'
import { Do } from 'fp-ts-contrib/lib/Do'

// type classes

interface Program<F extends URIS> extends M.Monad1<F> {
  finish: <A>(a: A) => Kind<F, A>
}

interface Console<F extends URIS> {
  putStrLn: (message: string) => Kind<F, void>
  getStrLn: Kind<F, string>
}

interface Random<F extends URIS> {
  nextInt: (upper: number) => Kind<F, number>
}

interface Main<F extends URIS> extends Program<F>, Console<F>, Random<F> {}

// instances

const programTask: Program<T.URI> = {
  ...T.task,
  finish: T.of,
}

/**
 * read from standard input
 */
const getStrLn: T.Task<string> = () =>
  new Promise(resolve => {
    const rl = createInterface({
      input: process.stdin,
      output: process.stdout,
    })
    rl.question('> ', answer => {
      rl.close()
      resolve(answer)
    })
  })

/**
 * write to standard output
 */
const putStrLn = flow(C.log, T.fromIO)

const consoleTask: Console<T.URI> = {
  getStrLn,
  putStrLn,
}

const randomTask: Random<T.URI> = {
  nextInt: upper => T.fromIO(R.randomInt(1, upper)),
}

// game

/**
 * parse a string to an integer
 */
function parse(s: string): O.Option<number> {
  const i = +s
  return isNaN(i) || i % 1 !== 0 ? O.none : O.some(i)
}

function main<F extends URIS>(F: Main<F>): Kind<F, void> {
  // ask something and get the answer
  const ask = (question: string): Kind<F, string> =>
    Do(F)
      .do(F.putStrLn(question))
      .bind('answer', F.getStrLn)
      .return(({ answer }) => answer)

  const shouldContinue = (name: string): Kind<F, boolean> =>
    Do(F)
      .bind('answer', ask(`Do you want to continue, ${name} (y/n)?`))
      .bindL('result', ({ answer }) => {
        switch (answer.toLowerCase()) {
          case 'y':
            return F.of(true)
          case 'n':
            return F.of(false)
          default:
            return shouldContinue(name)
        }
      })
      .return(({ result }) => result)

  const gameLoop = (name: string): Kind<F, void> =>
    Do(F)
      // run `n` tasks in parallel
      .sequenceS({
        guess: ask(`Dear ${name}, please guess a number from 1 to 5`),
        secret: F.nextInt(5),
      })
      .doL(({ guess, secret }) =>
        O.fold(
          () => F.putStrLn('You did not enter an integer!'),
          (x: number) =>
            x === secret
              ? F.putStrLn(`You guessed right, ${name}!`)
              : F.putStrLn(
                  `You guessed wrong, ${name}! The number was: ${secret}`,
                ),
        )(parse(guess)),
      )
      .bind('shouldContinue', shouldContinue(name))
      .bindL('result', ({ shouldContinue }) =>
        shouldContinue ? gameLoop(name) : F.of<void>(undefined),
      )
      .return(({ result }) => result)

  return Do(F)
    .bind('name', ask('What is your name?'))
    .doL(({ name }) => F.putStrLn(`Hello, ${name} welcome to the game!`))
    .doL(({ name }) => gameLoop(name))
    .return(constVoid)
}

export const mainTask = main({
  ...programTask,
  ...consoleTask,
  ...randomTask,
})

mainTask()

Thank you.

Add W-variants to Do, e.g. bindLW

πŸš€ Feature request

Current Behavior

const foo = Do(TE.taskEither)
  .bind("te1", TE.right<boolean, number>(1))
  .bindL("te2", () => TE.right<string, string>("wat"));

fails with:

Type 'TaskEither<string, string>' is not assignable to type 'TaskEither<boolean, string>'.
Type 'string' is not assignable to type 'boolean'.ts(2322)

Desired Behavior

const foo = Do(TE.taskEither)
  .bind("te1", TE.right<boolean, number>(1))
  .bindLW("te2", () => TE.right<string, string>("wat"))
  .return(identity);

Where foo would be TaskEither<boolean | string, { te1: number} & { te2: string }>.

Suggested Solution

πŸ€·β€β™‚οΈ Do is a complex beast.

Who does this impact? Who is this for?

This would alleviate the need to lift the first bind's Left into a union of all possible error types, which I believe is the current accepted workaround. This was the case for Either's chain too, until chainW was added recently. It would be great if we could get the same for Do.

Pattern Matching

πŸš€ Feature request

Would something like this be useful?

Current Behavior

Pattern matching is done using if/switch statements in conjunction with type guards.

Desired Behavior

It would be nice to have a more functional/concise syntax that still provides type safety and exhaustiveness checking (of course).

The following solution was inspired by Peter Fillo's β€œPattern matching” with Typescript done right.

If there is interest, I can create a pull request.

Suggested Solution

export const Tag = '_tag' as const

interface TaggedType {
  [Tag]: string | number | symbol
}

type TypeMap<T extends TaggedType> = {
  [K in T[typeof Tag]]: T extends { [Tag]: K } ? T : never
}

type PatternMap<M, T> = {
  [K in keyof M]: (e: M[K]) => T
}

export type Pattern<T extends TaggedType, U> = PatternMap<TypeMap<T>, U>

export function match<T extends TaggedType, U>(p: Pattern<T, U>): (e: T) => U {
  return (v) => p[v[Tag]](v)
}

It can be used as follows:

import * as E from 'fp-ts/lib/Either'

export const f = match<E.Either<boolean, number>, string>({
  Left: (e) => `L: ${e.left}`,
  Right: (e) => `R: ${e.right}`,
})

console.log(f(E.right(42))) // "R: 42"

The benefits become more obvious if there are more cases, the above is just for illustration.

Who does this impact? Who is this for?

All users?

Describe alternatives you've considered

Just using if/switch statements in conjunction with type guards.

Your environment

Software Version(s)
fp-ts 2.6.2
fp-ts-contrib n/a
TypeScript 3.9.2

Feature request: Do#letL

πŸš€ Feature request

I want to declare a variable in Do

Desired Behavior

.bindL("a", s => m.of(x))

Suggested Solution

.letL("a", s => x)

Curated list of examples and solutions

πŸ“– Documentation

In the Slack channel (FP Slack) very often people ask questions (from begginer to advanced level). For the more elaborate ones @gcanti (and others) usually share snippets with answers. Which are very useful and could help people in the future.

But Slack free plan means losing the history of the chat. Regardless of that, a chat application is not the best place to search for snippets.

My suggestion is to add a section in the docs with a curated list of those snippets. Maybe the question could be included as well.

The goal is to keep a record of all the "how do you do X in fp-ts (and friends)?"

Example

Here's and example question and the answer.

Question:

Given Array<IOEither<E, A>>. Count how many lefts and rights. Result should be IO<{ success: number, failure: number }> (or IO<[number, number]>).

Answer:

use wilt (from Witherable)

import { array } from 'fp-ts/lib/Array'
import { identity } from 'fp-ts/lib/function'
import { io } from 'fp-ts/lib/IO'
import { IOEither } from 'fp-ts/lib/IOEither'

declare const xs: Array<IOEither<Error, number>>

// result: IO<Separated<Error[], number[]>>
const result = array.wilt(io)(xs, identity)

Make `batchTraverse` pipe-able

πŸš€ Feature request

Make batchTraverse pipe-able.

Current Behaviour

Last invocation of batchTraverse requires the data (first) and the function (last):

import * as TE from 'fp-ts/TaskEither'
import { batchTraverse } from 'fp-ts-contrib/batchTraverse'


pipe(
  /** ... */
  (ass) => batchTraverse(TE.taskEither)(ass, f),
  /** ... */
)

Desired Behavior

batchTravers should be pipe-able with data-last:

import * as TE from 'fp-ts/TaskEither'
import { batchTraverse } from 'fp-ts-contrib/batchTraverse'


pipe(
  /** ... */
  batchTraverse(TE.taskEither)(f),
  /** ... */
)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.