-
Notifications
You must be signed in to change notification settings - Fork 114
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
does .ap work correctly? #206
Comments
EDIT: If I have many arguments that needs to be passed (rare case, but still), current implementation of For example, let's take a function like this: const fn = a => b => c => d => e => f => g => a + b + c + d + e + f + g; With current implementation, I have to write it like this: Maybe.of(1)
.ap(Maybe.of(2)
.ap(Maybe.of(3)
.ap(Maybe.of(4)
.ap(Maybe.of(5)
.ap(Maybe.of(6)
.ap(Maybe.of(7)
.map(fn))))))); but with Maybe.of(fn)
.ap(Maybe.of(1))
.ap(Maybe.of(2))
.ap(Maybe.of(3))
.ap(Maybe.of(4))
.ap(Maybe.of(5))
.ap(Maybe.of(6))
.ap(Maybe.of(7)); |
hi @overflowz looks like that would be much nicer for your flow.
But this seems to be very useful in 50% cases, so maybe there's a need to add another ap ( And also I'll start work on |
Hi! I think there should be an option to specify which one to use, because if other libraries are also depending on it (e.g. if another monad library expects to call I also tried to modify the Regards. |
Im not sure if we can allow such preconfiguration in monet (releasing 2 versions is an overkill) that would work with typescript typings. Ramda Fantasy states that it's compatible with fantasy-land but it's not in this case. Maybe there is need to tak one of these actions:
Another issue is that we'll not be able to define proper typings for the reversed ap version :( Maybe there is need to introduce …or maybe we can add a bunch of static operators: const add = Some(a => b => a + b)
const add1 = Applicative.ap(add, Some(1))
const sum = Applicative.ap(add1, Some(3)) but it's quite ugly :( |
here you can find an open issue stating that ramda-fantasy shoud update it's applicative to be compliant with fantasy-land: |
Yeah, they're ugly. As far as I know those static functions are available in sanctuary library and without being able to chain monadic operations seems not comfortable for me. About ordering that is reversed, I didn't knew that though. When I started learning FP in JS I used ramda with ramda-fantasy. Not sure what will be good solution for this tho :/ |
I was wondering, what if we check if e.g. Maybe's value type is a function and if so then we |
e.g. implementation for ap: function (other) {
var value = this.val
return typeof value === 'function'
? other.map(value)
: this.isValue ? other.map(function (fn) {
return fn(value)
}) : this
} This still passes all the tests and this works too: const monet = require('./src/monet');
const Maybe = monet.Maybe;
// logs Just(2)
console.log(
Maybe.of(x => y => x + y)
.ap(Maybe.Just(1))
.ap(Maybe.Just(1))
);
// logs Nothing
console.log(
Maybe.of(x => y => x + y)
.ap(Maybe.Nothing())
.ap(Maybe.Just(1))
); EDIT: Might be a terrible approach, pardon me. I'm still wrapping my head around FP world. |
Sorry for creating another issue. I've got some thoughts about that: #232 |
I think that we can create separate method for swapped (haskell style) ap. But this has to be typesafe - se we need to investigate that there is a way to express the value check in TypeScript :) |
just a quick n dirty example to give an idea, wouldn't this work? (I'm aware that I'm using class Maybe<T> {
private constructor(
private readonly value: T,
) { }
static of<T>(x: T): Maybe<T> {
return new this(x);
}
map<R>(fn: (value: T) => R): Maybe<R> {
return Maybe.of(fn(this.value));
}
ap1(value: Maybe<T extends (arg: infer T) => any ? T : never>): T extends (...args: any) => infer T ? Maybe<T> : never {
return value.map(this.value as any) as any;
}
} |
@overflowz this works for me. Just let's decide if it's |
@overflowz just after further investigation I found out that it doesn't proparly handle |
ouch. I'll investigate further when I have a time. |
class Maybe<T> {
private constructor(
private readonly value: T | null,
) { }
static of<T>(x: T): Maybe<T> {
return new Maybe(x);
}
static none<T>(): Maybe<T> {
return new Maybe<T>(null);
}
map<R>(fn: (value: T) => R): Maybe<R> {
return this.value !== null ? Maybe.of(fn(this.value)) : Maybe.none();
}
ap1<V>(value: T extends (arg: infer I) => V ? Maybe<I> : never): T extends (arg: any) => infer R ? Maybe<R> : never {
const v = this.value;
if (isNull(v)) {
return this; // still not good :()
}
if (isFn(v)) {
return value.map(v) as ReturnType<typeof v>;
}
throw Error();
}
}
function isFn(fn: any): fn is ((arg: any) => any) {
return typeof fn === 'function';
}
function isNull(fn: any): fn is null {
return fn === null;
}
const a = Maybe.of((a: string) => (b: string) => a + b);
const b = a.ap1(Maybe.of('asdf')).ap1(Maybe.of('asdf')); This way it's almost good (see - no |
@ulfryk, Also, As far as i know, import { Functor } from 'monet';
interface Applicative<T> extends Functor<T>/* Every applicative is a functor? Shouldn't it inherit Functor interface? */ {
ap<V> (afn: Applicative<(val: T) => V>): Applicative<V>
apTo<V> (value: Applicative<V>): T extends (arg: V) => any ? Applicative<ReturnType<T>> : never;
'fantasy-land/ap'?<V> (afn: Applicative<(val: T) => V>): Applicative<V>
}
type x = { foo: string };
type y = { bar: string };
declare const a: Applicative<(v: x) => y>;
declare const b: Applicative<x>;
declare const c: Applicative<y>;
a.apTo(b).map(value => value.bar); // correct. Value has `y` type
a.apTo(c).map(value => value.bar); // compilation error. `never` type has no `.map` property |
@ulfryk should it also cover the undefined value (besides null)? also the above looks much cleaner to me (mine was just PoC). |
@overflowz use what you already have. Actually you will probably not reauire to manually handle null or undefined as |
Maybe.prototype.apTo = function(value){
return value.ap(this)
}
|
What is the status of this being released? I see it's in the development branch. How does development become master and get published? What can I do to help? |
Ahh yes... I did not have much time lately and looks like GH CI integrations have changed and it stoped working (nightly version should release after each merge to So when Travis integration is fixed we need to create a releas PR - with proper version in package.json, updated CHANGELOG and proper tag (in latest commit). When it's get merged to If you can help with fixing Travis integration @jderochervlk - I can proceed with release :) ( will also add all this info to CONTRIBUTING.md ) |
@iLikeKoffee I did not see any travis scripts triggered by #238 actually, there is probably some change in settings required to make it work. I will try to resolve it this week. EDIT: but I can see positive outcome - nightly was released :)
|
@iLikeKoffee I can't see the log :( |
anyway some nightly versions released:
|
@ulfryk Are you going to release 0.9.2? |
@iLikeKoffee yes, just when I clean up few things ( probably during weekend ). |
|
Hi, first of all, I'm new into FP and playing around.
I'm trying to find better alternatives to
ramda-fantasy
for monads. From all the implementations I've searched, I found monet.js most suitable (and great work btw!)The problem I have currently. Here's an example I'm using from
ramda-fantasy
with.ap
But when I'm trying same way in monet.js, all I get is errors saying
fn is not a function
.Question is, why it does not work the same way and/or how can I do exact same thing in monet?
Regards.
The text was updated successfully, but these errors were encountered: