Giter VIP home page Giter VIP logo

Comments (23)

bergus avatar bergus commented on August 18, 2024 2

appWithValue.ap(appWithFunction)

looks really odd to me. Applying functions with multiple arguments doesn't seem to work well - or is quite ugly, if we look the linked example:

var person = function(forename, surname, address){…}.curry()
var maybePersonResult = maybeAddress
                        .ap(maybeSurname
                            .ap(maybeForename
                                .map(person)))

Not only is there much nesting, but also the order of the arguments is inverted. Having used .map() instead of .ap(Maybe.of()) might save characters and an explicit Maybe reference, but doesn't make it look better.

The appWithFunction.ap(appWithValue) order is better imho:

Maybe.of(person).ap(maybeForename).ap(maybeSurename).ap(maybeAddress)
// or even
Maybe.of(person).ap(maybeForename, maybeSurename, maybeAddress)

It wouldn't be more consistent to flip it just because we have flipped fmap to become a .map method of a Functor instance - Applicatives are more than Functors and .ap can already be a method of an Applicative instance.

from fantasy-land.

puffnfresh avatar puffnfresh commented on August 18, 2024

I guess I copied Haskell's <*> infix operator. Just like <$> (i.e. infix fmap) - it's flipped to what it probably should be.

It'd probably be more consistent to flip it (i.e. it would look more like other functors).

What should we do about updating the specification? I have no hesitation to release new versions of my projects but does anyone have a project where they can't or don't want to change the order of ap?

from fantasy-land.

joneshf avatar joneshf commented on August 18, 2024

I think this goes back to #24. However, we haven't really been keeping up with updating the version number to begin with. If you'd like I can go back to when version 0.0.1 was first "released" and look through the changes since then, tagging and whatever. Or we can just start right now with a set version, and keep everything semver'd from here on.

from fantasy-land.

jneen avatar jneen commented on August 18, 2024

There's an alternative definition of Applicatives that uses a "join" or "seq" operator instead of "ap".
Here's how join (unrelated to join :: m (m a) -> m a) would look (note: code in this comment is pseudo-haskell):

class Functor f => Joinable f where
  pure :: a -> f a
  join :: f a -> f b -> f (a, b)

It's equivalent to ap:

join u v = ap (map (,) u) v
ap u v = map (\(f, x) -> f x) (join u v)

And it even comes with equivalent laws:

join (pure x) v = map (x,) v
join v (pure x) = map (,y) v
join (map f u) (map g v) = map (f *** g) (join u v)
join u (join v w) = map (\(x, (y, z)) -> ((x, y), z)) (join (join u v) w)
map f (pure x) = point (f x)

The "ap"-based one seems to be the best in Haskell since functions are auto-curried and tuples are non-recursive. But in JS we can use heterogenous lists instead, so "join" might be more natural to express. In fantasyland, I guess it would be something like "a.join(functors)" is a functor of a combined array of results from the given functors.

Anyways, slightly rambly, but this represents the way the seq method is used in Parsimmon, which is much more naturally usable than ap (in fact, Parsimmon's ap is implemented in terms of seq). It'd be worth considering whether to standardize this sort of interface, since I can imagine it coming up quite a lot.

from fantasy-land.

jneen avatar jneen commented on August 18, 2024

related to #56, although liftN still requires a function.

from fantasy-land.

jneen avatar jneen commented on August 18, 2024

In Parsimmon I've recently gone with the join implementation I mentioned here, although I renamed it to seq to match Parsnip. Basically, seq :: [Parser *a] -> Parser [*a] where *a is heterogenous. ap is implemented in terms of this primitive.

from fantasy-land.

puffnfresh avatar puffnfresh commented on August 18, 2024

Yeah, this needs to be fixed. PR would be awesome!

from fantasy-land.

SimonRichardson avatar SimonRichardson commented on August 18, 2024

Should we flip the order of ap, or just live with it?

from fantasy-land.

rpominov avatar rpominov commented on August 18, 2024

I'm having trouble typing ap() with Flow, ended up with this:

class Stream<T> {

  // Apply
  ap<A,B>( other:Stream<A> ): Stream<B> {
    // In order for .ap() to work `this` must be a `Stream<A => B>`,
    // but I don't know how to express that constraint in Flow, so just use `any`
    const streamF:BasicStream<any> = this.observe
    return new Stream(bs.ap(streamF)(other.observe))
  }

}

Would be straightforward if it was other way around.

from fantasy-land.

joneshf avatar joneshf commented on August 18, 2024

That is quite unfortunate. Can you actually write the other way with flow?

from fantasy-land.

rpominov avatar rpominov commented on August 18, 2024

Sure, with reversed version of ap it will look like this:

class Stream<T> {

  ap<A>( other:Stream<( x:T ) => A> ): Stream<A> {
    return new Stream(bs.ap(other.observe)(this.observe))
  }

}

from fantasy-land.

rpominov avatar rpominov commented on August 18, 2024

For the record: not a big problem for me, just wanted to add my two cents :)

from fantasy-land.

SimonRichardson avatar SimonRichardson commented on August 18, 2024

I've been hit with this recently as well. So the question is how do we change it, because I think we should!

Could we maybe rename ap to something else, or do we say if you depend on the new fantasy-land #92 ap works like this now?

from fantasy-land.

rpominov avatar rpominov commented on August 18, 2024

We could certainly use NPM to help us manage changes like that after libraries start depending on FL.

We could do for example:

  • 1.0 backward compatibility release with unprefixed names and no changes to the spec
  • 2.0 adds prefixes therefore providing clashes safety, but still no changes to the spec
  • 3.0 no changes in method names, but includes changes to spec like this and #88

Then libraries could specify appropriate versions range in their peerDependency to fantasy-land, and consumers won't be able to use two incompatible libraries (they won't be able to install version of fantasy-land that satisfies peerDependency for all of incompatible libs).

from fantasy-land.

SimonRichardson avatar SimonRichardson commented on August 18, 2024

I'd rather have 3.0 out before 2.0 💃

from fantasy-land.

rpominov avatar rpominov commented on August 18, 2024

No preference on that matter from me :)
We could also squash 3.0 and 2.0 to one version, btw.

from fantasy-land.

bergus avatar bergus commented on August 18, 2024

So you only want to change this because flow's type system is not sophisticatd enough?

from fantasy-land.

rpominov avatar rpominov commented on August 18, 2024

Yep, and also the fact that it's inconsistent with map and chain and was a mistake from the beginning (see #50 (comment))

Feel free to discuss in the PR: #145

from fantasy-land.

Avaq avatar Avaq commented on August 18, 2024

I think this can be closed now, no?

from fantasy-land.

SimonRichardson avatar SimonRichardson commented on August 18, 2024

Indeed it can!

from fantasy-land.

char0n avatar char0n commented on August 18, 2024

Sorry for commenting on closed issue, but It may help somebody dealing with the same issue as I did. I heavily use monet.js algebraic structures along with ramda. As @cwmyers pointed out, applicatives in monet.js are not compatible with fantasy-land spec. Though one cannot use ramda's liftN to work with monet's applicates. I implemented liftFN to create interop for monet.js and ramda. It is part of ramda-adjunct and you can find more information in the docs.

from fantasy-land.

evilsoft avatar evilsoft commented on August 18, 2024

@char0n looks like ramda#1900 was merged. So soon, very soon, once ramda releases its next version we should all be gtg!!

from fantasy-land.

char0n avatar char0n commented on August 18, 2024

@evilsoft I've just tried using lift from master branch of ramda, but it still doesn't work with monet.js algebraic structures. liftFN from ramda-adjunct still working. I am still investigating the issue...

I have one additional question regarding composition of Apply spec regarding v.ap(u.ap(a.map(f => g => x => f(g(x))))) is equivalent to v.ap(u).ap(a) (composition)

const add3 = curry((a, b, c) => a + b + c);

const m10 = Maybe.Some(10);
const m15 = Maybe.Some(15);
const m17 = Maybe.Some(17);

m10.ap(m15.ap(m17.map(add3)))

What is the eqvivalent of v.ap(u).ap(a) in my real code example ? Is this type of composition still possible when the ap argument must be apply of a function ?

Update:
monet.js PR #112 makes monet.js compatible with fantasy-land spec and next version of ramda (>0.23.0). Use [ramda-adjunct](https://github.com/char0n/ramda-adjunct} and liftFN for time being.

from fantasy-land.

Related Issues (20)

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.