-
Notifications
You must be signed in to change notification settings - Fork 373
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
Change the spec so it would require prefixed method names #92
Comments
👍 This would make life much easier for Ramda which is a generic functional programming library for JS, but which will work well with types implementing the FantasyLand spec: R.map(square, [1, 2, 3]); //=> [1, 4, 9]
R.map(square, Just(5)); //=> Just(5).map(square); //=> Just(25)
R.map(square, Nothing); //=> Nothing.map(square); //=> Nothing
R.map(square, Right(7)); //=> Right(7).map(square); //=> Right(49)
// etc. While we do this sort of dynamic dispatching on a number of our functions, there is a special place in our hearts for the FantasyLand specification, and I would love to see this work more generally than it does now. We could easily code to dispatch to such FL versions first if they're defined and after that to matching named function. This would mean that Ramda might integrate better with Bacon and other libraries that have conflicts with the FL names. |
Why not just put the fantasy-land library in a wrapper and expose your new So 👎 from me. On Sat, 23 May 2015 20:47 Scott Sauyet notifications@github.com wrote:
|
The problem is that FantasyLand wants to claim ownership of all of these names:
With the exception of If a user has a type that uses one of these words for another meaning -- With the suggestion here, she could easily add the FantasyLand types, and any tool that uses the types in a generic way and any algorithm written against these algebraic data types would work as they do today, But we gain a more declarative sense too. Right now, the existence of a |
On the naming: Array's map should allow it to be a Functor. Patching monkeys to add support is not something I'm in favour of. @CrossEye something with chain doesn't have to have
|
That way you're not exposing any fantasy-land functions that you don't On Mon, 25 May 2015 05:20 Brian McKenna notifications@github.com wrote:
|
Right, but we could also add |
Also the spec can be stricter this way, e.g. it can demand that Also 👍 on |
@SimonRichardson: Perhaps I'm not being very clear. Ramda is not trying to implement the specification at all. (Well, there is a side project, but that's not the point) Instead, Ramda is presenting a more functional API centered around functional composition. Many of its functions work on lists, and some of these overlap with the FantasyLand methods. For these and some others we do a form of dynamic dispatch. Thus
Yes, sorry, but the point should still be clear. I really like the way the transducers protocol has been handled as a low level library that's out of the users' way, and which will not interfere with other design of their tools. I would love to see FL do the same. |
I think what would benefit this proposal would be more clarity in what is suggested. It's kind of hard to understand what the point is, who it benefits, what would change, how to mitigate confusion, and what current libraries would need to do. It sounds like the proposal can help foster adoption, but it's hard to see how. |
@CrossEye I might reluctantly give in on this, but I really think that as long as this is an alias to the functions then it could work. I absolutely think that the functions should stay as is and that your namespaced aliases should just be sugar in the spec. I use fantasy-land by hand and I do know what |
I'll try to summarize.
Only names of the methods that the specification require to implement.
Also only change the names.
Good point! But I don't see a problem here, all libs that implement FL, will be able to add both long and shorter name with the same functionality. They even can state in the docs that they "implement FL with both long and shorter names". Also you'll can use libs like Ramda instead of directly call FL methods, if you like, but again no one stops anybody to add methods with short names and use them directly. |
Unfortunately, this would likely only work if it were the other way around, if users implemented |
I'm highly in favor of making this change. The arguments given so far has been splendid but there is another angle as well: Currently fantasy land requires data types to implement a sensible object oriented API. It completely wrong for a specification that is coming from a functional angle. I've created a library that exposes reactive streams that implements the applicative interface. This means that the streams must have a It is very annoying that one has to implement a object oriented API that can easily be mistaken for a genuine OO API in an otherwise completely functional library that makes no use of methods.
|
That is of course easily solvable by using a function like this |
@paldepind I vote for you to make a wrapper and expose what you need to :) |
@SimonRichardson How would a wrapper help expect making it more cumbersome to use my library with consumers of fantasy land adts? That is not a solution. I am not satisfied that the only counter argument in this discussion has been "I just don't feel fantasy-land should do this IMO." This is not about feelings. This is about making it easier and less problematic for libraries to expose adts and for consumers of adts to be safe and certain that they are dealing with the real thing. And not any of the thousand unlawful |
It's clearly understandable why this spec was written the way it was. There is a real desire for this to simply work where possible with existing code. Use But this can break down eventually for reasons already expressed. People really would like to describe their types according to the FantasyLand specification, and use them with tools that are ready to work with Functors, or Applicatives, or whatever. But because of competing concerns in their domain, they can't really use the names reserved by FantasyLand for their Functor or Applicative methods. Or they have preexisting functions with similar behavior but a different API that their users are already far too long accustomed to use. Suddenly FantasyLand's easy solution is not so simple. Users can get around this only by writing wrappers for any type that has these problems, a horrible solution. Libraries that work with these types cannot get around this at all. But FantasyLand has a simple fix. It's worked well for Transducers and for the Iteration protocol; it really seems like a good solution here too. |
@paldepind why bother at all, if map does what it's supposed to do
@CrossEye I would agree, but fantasy-land isn't doing anything magical here. It's not setting up things for mutability nor is it doing anything grossly underhanded. I see no point in it! The methods in the specifications are really simple, there is no ambiguity about what happens and when it happens. If you want to add a fantasy-land protocol then maybe that's the way to move forward. I just don't see the need to make something that is inherently simple, complicated. Fantasy-sorcery implements a generic map method and I've used this many times in the past without issue, again, maybe it's worth moving forward with this. It might actually help if the spec was versioned, then this could be |
@CrossEye I very much agree with you. But I have to complain about this again:
This is a similar claim to what @puffnfresh wrote earlier. But it is still only superficially true. Consider the following completely normal (albeit contrived) usage of an applicative var multiply = curry(function(x, y) { return x * y; });
function multWith(functor) {
return functor.map(multiply);
} Here |
You can say that. But the point is that it causes confusion for users. They see the |
Then it's not fantasy-land compliant. It's that simple. |
@SimonRichardson Just wonder, what is the purpose of fantasy-land in your opinion? Please, don't get me wrong, it's a serious question, not a troll. It's just seems like we see the purpose of this spec differently, which is the source of all the confusion about this proposal. |
Of course? Don't you see that the problem arises as soon as someone wants that library to become compliant? |
@rpominov I didn't take it as such :)
I 💯 agree with you about this, it seems like libraries are wanting to align to the specification, which is completely understandable. I just don't see the reason why you would want to hide various methods because it might confuse people. If you think your library might confuse people by how From my point of view, I would like to code to the specification without additional complexity, like I can already do now. I'm all for progressive changes to the specification, but I don't see the need for the namespaced complexity as
Adding another |
I agree. I was speaking of the reasons the specifcation was written is what is on the surface the easiest manner, but which is in the end more complex than is necessary. Note, though, that your example depends on a style of |
And because FantasyLand has chosen to define itself in terms of common words such as 'map', 'empty', 'reduce', 'chain', etc., such users can't make their libraries tantasy-land compatible. Maybe others feel this is fine, and only those that can throw aside whatever other constraints they have upon them are worthy of implementing this spec. But I feel it's a shame. I would rather these ideas were easier for users to implement. |
|
If people vote that the spec should be namespaced, then I think semver should be pushed through at the same time, then at least we can live together. |
What if we publish a const fl = require('fantasy-land')
fl.map === 'fantasy-land/map' // we may use Symbols with this approach as well, I think So the libraries that use FL in any way will add that package as a Peer Dependency with as wide versions range as possible. And use constants that the package exposes as method names in any place they use FL spec. For example we may have a library that provides // my-map-lib/index.js
const fl = require('fantasy-land')
exports.map = (fn, target) => {
if (Array.isArray(target)) {
return target.map(fn)
}
if (target && target[fl.map]) {
return target[fl.map](fn)
}
}
// my-map-lib/package.json
{
"peerDependencies": {
"fantasy-land": "*"
}
} Then we may have a library that provides some type that implements Functor: // my-id-lib/index.js
const fl = require('fantasy-land')
exports.Id = function(x) {
this._x = x
}
exports.Id.prototype[fl.map] = function(fn) {
return new exports.Id(fn(this._x))
}
// my-id-lib/package.json
{
"peerDependencies": {
"fantasy-land": "*"
}
} And finally we can use both of libs in our app code: // my-app.js
const {map} = require('my-map-lib')
const {Id} = require('my-id-lib')
const foo = new Id(1)
const bar = map(x => x + 1, foo)
bar._x // 2
// package.json
{
"dependencies": {
"my-id-lib": "1.0.0",
"my-map-lib": "1.0.0",
"fantasy-land": "1.0.0"
}
} Backward compatibility for freeWhat is good about this approach is that we can publish first version of So if I want to access FL methods directly in my code, I can install // my-app.js
const {map} = require('fantasy-land')
const {Id} = require('old-lib')
const foo = new Id(1)
const bar = foo[map](x => x + 1)
bar._x // 2
// package.json
{
"dependencies": {
"old-lib": "1.0.0",
"fantasy-land": "1.0.0"
}
} This will work just fine, although won't save us from name clashes. So then we can publish |
Actually @robotlolita has suggested exactly that. Sorry I didn't re-read comments before writing this. So the Cons was:
I think peer dependencies solve the first, and we shouldn't have any problems with Realms if we use strings and not Symbols (don't know why we should use Symbols anyway). |
Create a PR and then we can see what it feels like to use :) On Sun, 17 Jan 2016, 17:58 Roman Pominov notifications@github.com wrote:
|
I've had a play with it and it works for me. I'm happy to merge this one in - @puffnfresh you happy with this? |
This is now merged 👍 Shall we close and open a new issue discussing namespaced prefixes in the future? |
That's great! 🎉 🎊 Yeah, a new issue would be nice, this one a bit too long and hard to read. |
One point were made here by me and others is that with unique prefixed names we can tell for sure if an object has a compliant FL method. But it doesn't mean it has an algebra (doesn't mean that the method obeys certain laws). For example if an object have I realized it just recently and thought it worth mentioning here. |
I think there's no way to tell that in general. This is not even a Javascript issue; it must be fairly fundamental and related to issues like the halting problem and Rice's Theorem. The advantage of prefixed names is that with them it becomes abundantly clear that someone is meaning to create types that adhere to the laws for the given algebra. Code that tries to do something generically against any sort of |
Yeah, I wouldn't worry too much about The problem seems solvable though, at least in JavaScript. We could require a property on each value with the list of algebras it implements. E.g. |
Ok, I thought you were worried about a different problem. Oh, yes I'm sure it's possible to have something be both a I'm still in favor of a TypeRegistry version instead. But I don't know when, or at this point even if, I'll get back to my attempt at this. |
@CrossEye function ap(f, ma) {
return f.chain(function(x) {
return ma.map(function(a) {
return x(a);
});
});
} I don't have a proof, but I have a feeling that |
Yes, that's in the spec.
I'd be very very interested to see such a proof if anyone knows one. |
I propose to change the spec so it would require more unique method names. For example, instead of
ap
method, a@@fantasy-land/ap
. It can be called asfoo['@@fantasy-land/ap']()
.This would serve two purposes:
This also will allow to create a polyfill that adds fantasy-land support to native JS data structures. It relatively ok to add
@@fantasy-land/ap
method toArray.prototype
, but less ok to addap
.Also libraries like Bacon, for example, will be able to add fantasy-land support, as for now it problematic with map method, for instance, as it not strictly compatible with the spec, but they could add
@@fantasy-land/map
that is.I think this change could significantly speed up the adoption of fantasy-land specification.
The idea inspired by transducers protocol, seems like it worked out for them pretty well.
See also discussion on Gitter: https://gitter.im/fantasyland/fantasy-land?at=553cb82d20328f114ca36f0f
The text was updated successfully, but these errors were encountered: