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

Applicative.apOn(value: Applicative<V>) proposal. #232

Closed
iLikeKoffee opened this issue Oct 14, 2020 · 2 comments
Closed

Applicative.apOn(value: Applicative<V>) proposal. #232

iLikeKoffee opened this issue Oct 14, 2020 · 2 comments

Comments

@iLikeKoffee
Copy link
Collaborator

Hello. First of all - thank you for awesome library. This is really great.
I've got a little feature request.

AFAIK, common usage of Applicatives in haskell - applying function with N arguments to values.
Just, something like this(example from here):

pure (+) <*> Just 3 <*> Just 5 
> 8

If i want to achieve the same behaviour with Monet, i should do something like this:

const maybeA = Maybe.of(10),
      maybeB = Maybe.of(12);

const curriedSum = a => b => a + b;
const applicative = Identity.of(curriedSum);

maybeB
  // This cannot be chained, so if we have, for example, function of 3 or more arguments, code will look much worse,
  // Something like this: maybeD.ap(maybeC.ap(maybeB.ap(maybeA.ap(applicative)))) and so on.  
  .ap(maybeA.ap(applicative))  
  .forEach(v => console.log(v))

My proposal is to create an alias for Applicative.ap with swapped arguments(this and value) order,
Quick & dirty proof of concept:

import {Maybe, Identity} from 'monet';

Identity.prototype.apTo = function(value){
  return value.ap(this)
} 

const maybeA = Maybe.of(10),
      maybeB = Maybe.of(12);

const curriedSum = a => b => a + b;
const applicative = Identity.of(curriedSum);

applicative
  .apTo(maybeA)
  .apTo(maybeB)
  // ^ this can be chained as many times as number of arguments of our curried function and requires no nesting.
  .forEach(v => console.log(v))

JS cannot apply functions in haskell-like style (I mean firstArg f secondArg), so this alias seems suitable to me.
If there is no objections against this proposal i would gladly implement it and provide a PR.

P.S. PoC in CodeSandbox

@ulfryk
Copy link
Member

ulfryk commented Oct 15, 2020

@iLikeKoffee I really like this idea, just have to think about typesafety.

declare const applicative: Maybe<(a: number) => (b: number) => number>;

applicative
  .flatMap(fn => maybeA.map(a => fn(a))) // ts knows that `fn` is function accepting number, returning function
  .flatMap(fn => maybeB.map(b => fn(b))) // ts knows that `fn` here is a funciton accepting number, returning number
  .forEach(v => console.log(v)) // ts knows that `v` is a number

But above example is ugly :(

We should investigate if there is a nice way to express apTo in TS and if not , maybe add it with some tradoffs (runtime checks? ).

But anyway - let's move this discussion to #206

(and yes, it's a pity that JS doesn't have infix operators 🙃 )

@iLikeKoffee
Copy link
Collaborator Author

Closing, as duplicate of #206

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