-
Notifications
You must be signed in to change notification settings - Fork 376
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
derivable methods are contradictory #132
Comments
It means you don't need to actually write the specific implementation for your data type. You can use that derived version that is general to ALL // Throw this in some library on npm.
function mapFromApplicative(f) {
return this.of(f).ap(this);
} // This is your application code.
function Identity(x) {
this.map = mapFromApplicative;
this.ap = function(other) {
return new Identity(x(other.runIdentity));
};
this.of = function(y) {
return new Identity(y);
};
this.runIdentity = x;
} Or you can use a library that takes into account the full spec and provides this derivation for you if you don't write it yourself. So you'd do something like: // This would be similar to https://github.com/fantasyland/fantasy-sorcery/blob/287304318f4f21f5ec2dc2c269a9924a8748a866/index.js#L16-L21
// But it would check for the `Applicative` case as well.
const someBadAssLib = require('someBadAssLib');
function Identity(x) {
this.ap = function(other) {
return new Identity(x(other.runIdentity));
};
this.of = function(y) {
return new Identity(y);
};
this.runIdentity = x;
}
someBadAssLib.map(x => x + 10, new Identity(3)); |
After reading the first half of your comment I was able to resolve the contradiction in my mind. For a data type to satisfy the Functor specification it must provide a (compliant) The second half of your comment reintroduces the contradiction. You suggest that Your interpretation of the spec appears to be that to satisfy the Functor specification a value must:
If this is how the spec is intended to be interpreted, we should:
|
Certainly a close reading of the spec makes this feel contradictory. Without a compiler to supply the missing |
The first half of my reply was meant to be the actual answer. The second half is just some interesting thing you can do.
We shouldn't push the burden to support this derivation on library authors though. If they want to, great. But they can also just blow up if you don't provide the correct function. Should ramda have to check at least those four different derivations (and more once the spec grows) because some person is too lazy to write a couple of lines? That seems unnecessary. If ramda wants to, there's nothing to stop it. But to make it a requirement is too much in my book. |
In Static Land I have a In SL there probably will be a requirement that when you create a type you must apply |
Hmmm. Are you saying that this:
does not actually mean that your spec-conforming type may skip implementing |
I'm very confused by your question. |
Sorry, been offline a few days. And yes, that was poorly worded. To be an |
Bit of an outside perspective. In Functional Programming in Scala (basis for ScalaZ and Cats), they keep Where So I believe you do need to find |
Per the spec https://github.com/fantasyland/fantasy-land/blob/885146b75fb055f84eccb20db6dacbb8050f6bc5/README.md#general, which I did not know existed in my previous replies, If you implement |
As your picture shows, you only need |
IMO, it would be easier for everybody if the spec would require that all methods that a type claims to support must be added to the type. It's not a big deal for the person who implements a type. They can easily add the method by copy-pasting code from the spec. |
@joneshf absolutely, you can implement the core combinators and have the derived combinators do the rest of the work. However, the end result should net you all the functions I mentioned. That's what I meant to say. Thanks for pointing that out |
Somehow I lost the long reply I'd written here. I don't have the heart to type it again at the moment. The basic gist was that if the interpretation from @joneshf is right, the burden on libraries that want to work generically with these types is fairly large. I have to implement I agreed with this from @rpominov:
and wondered if this whole "can be derived from" bit should simply not be ported over from compiled languages to JS. |
I think this should be in the spec but with somewhat different meaning. Derived methods add restrictions on how methods can be implemented, and I think this should be explicitly stated in the spec:
|
Yes, I could certainly buy that. |
You don't have to implement anything in ramda, nor would @davidchambers have to implement anything in sancturary, etc. That work can be offloaded to a spec compliant helper library. That is the point of this generality. Only one library really needs to exist that does the derivation. And it can be used for ANY data type. In actuality, the derivations could be provided by this repo. So you'd only have one dependency, and it would be tied to the spec as well. |
Ah, makes sense. Sorry for misunderstanding. |
But will it be convenient to always use this lib on method call side? I mean do we have to do something like Wouldn't it be better if type implementer would do |
I would be very opposed to a specification also serving as a de facto necessary tool in implementing the spec. A little too much tail-swallowing for me. But there's a major question, if @davidchambers is not right about there being some ambiguity in the specification: Such a tool is actually quite central to using the spec in a generic manner. So why hasn't it been created yet? The spec as been out for three years. Has anyone seen one in the wild? Not having seen one makes me believe that most implementors are thinking of the spec the way @rpominov is suggesting: if I don't want to customize |
As mentioned earlier: #132 (comment) This library has existed for the past three years: https://github.com/fantasyland/fantasy-sorcery |
It's not a requirement that you use a library like If someone wants to reimplement all this stuff they can do so. But one of the purposes of this spec is to remove duplication. |
Ahh, Ramda might well choose to redo it on its own, as it has so far avoided all external dependencies, but that may have to change as FL grows up in any case, so we'll see. |
@puffnfresh, could you state definitively how to resolve the contradiction? The rest of us are guessing. |
Continuing studies in @puffnfresh exegesis: #92 (comment) cc/ @davidchambers |
@davidchambers clarify the spec 👍 |
I've made my best effort to do so in #134, @puffnfresh. What do you think? Your position still isn't clear to me. If you'd like to remove
and similar sentences from the spec, I'll open another pull request to do so. I would much prefer to keep this sentence and to remove the sentence which contradicts it (as in #134). A data type should provide all the appropriate methods. If it does not, a user of a data type which claims to be a functor cannot write: Identity(42).map(f); Instead, she must: // id :: Identity Number
const id = Identity(42);
typeof id.of === 'function' && typeof id.ap === 'function' ?
id.of(f).ap(id) :
typeof Id.of === 'function' && typeof id.ap === 'function' ?
Id.of(f).ap(id) :
typeof id.of === 'function' && typeof id.chain === 'function' ?
id.chain(x => id.of(f(x))) :
typeof Id.of === 'function' && typeof id.chain === 'function' ?
id.chain(x => Id.of(f(x))) :
// else
id.map(f); This is intolerable as far as I'm concerned. I hope you agree. :) If we allow derivations, we must discourage the direct use of Fantasy Land methods, and encourage the use of libraries which provide derivation-aware Things will be much simpler if we remove the exceptions. Authors of data type libraries will be forced to provide the derivable methods, but I argue that they do so anyway to allow their libraries to be usable stand-alone. Furthermore, these authors are free to derive these methods, perhaps even by importing a library which provides FL derivations. The
|
If that is the interpretation taken, I would recommend supplementing these sentences rather than removing them. So they would read something like:
|
That sounds good to me, @rjmk, if we take that path. It'd still be simpler not to have these exceptions. Hopefully Brian agrees. :) |
👍 |
Applicative:
Apply:
Functor:
So a value that implements the Applicative specification must provide a
map
method.Here is the contradiction:
Is there a semantic difference between "implements the Applicative specification" and "satisfies the specification of an Applicative"?
I'm wondering whether Ramda's
map
function should operate on a value which providesof
andap
but notmap
. The fact that derivations are mentioned in the spec suggests they are desirable, but as written it doesn't seem correct to derive implementations.The text was updated successfully, but these errors were encountered: