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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do with filter (if) #51

Open
Gurimarukin opened this issue Feb 21, 2020 · 7 comments
Open

Do with filter (if) #51

Gurimarukin opened this issue Feb 21, 2020 · 7 comments

Comments

@Gurimarukin
Copy link

Gurimarukin commented Feb 21, 2020

馃殌 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?
@cyberixae
Copy link
Sponsor

This would probably work for monads that are Filterable. Whether or not all Monads are Filterable, I do not know.

https://gcanti.github.io/fp-ts/modules/Filterable.ts.html
https://gcanti.github.io/fp-ts/modules/FilterableWithIndex.ts.html

@cyberixae
Copy link
Sponsor

It seems a Monad is not necessarily Filterable. However, you could implement your own For for things that are both Monad and Filterable. It could use 麓Do麓 for the operations that do not require for the type to be Filterable.

@cyberixae
Copy link
Sponsor

I made an experimental implementation of For notation. However, I can not figure out how to reuse code from the DoClass so I had to use copy/paste to make it work. Other than that it seems to work. See https://github.com/cyberixae/fp-ts-contrib/commits/implement_for_notation

@Gurimarukin
Copy link
Author

Gurimarukin commented May 4, 2020

Oh wow! Nice job!
I was thinking about the method's name: wouldn't this be closer to the usual conventions of fp-ts:

For(option)
  .bind('n', some(12))
  .filter(2 > 3)
  .filterL(({ n }) => n < 10)
  .return(({ n }) => n)

But I don't see cases where filter isn't lazy.

@cyberixae
Copy link
Sponsor

The L stands for lambda. I think it would be nice to have the constants have a suffix instead of the lambdas since the constant versions are more of a special case. I don't think the L suffix naming is from fp-ts. I'm not sure if it makes sense to add the For notation to fp-ts-contrib. Maybe you could fork it and create your own npm package that implements the for notation. You could then make it more appealing to people with Scala background. Just an idea though. Don't feel obliged to do so.

@Gurimarukin
Copy link
Author

I always thought that in fp-ts the L stands for lazy. In v1 of fp-ts, for instance for Option.getOrElse, there used to be both getOrElse et getOrElseL signatures.
https://github.com/gcanti/fp-ts/blob/1.x/docs/modules/Option.ts.md#getorelse-method-1

I have no problem with not adding For to fp-ts-contrib. This was just a suggestion and I managed to make my code work without it :)

@cyberixae
Copy link
Sponsor

Perhaps it was used for lazy in fp-ts however the Do notation was developed separately. See https://paulgray.net/do-syntax-in-typescript/#do-l-bind-l-sequence-sl-let-l-variants

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

2 participants