-
Notifications
You must be signed in to change notification settings - Fork 378
add Compactable algebra #278
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
Conversation
|
Good job! Find throwing me a mention for this? |
Adding a link to Control.Compactable do you mean, @Fresheyeball? That sounds good to me. |
|
|
||
| ```js | ||
| // Nothing :: Maybe a | ||
| const Nothing = {isJust: false}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this be 'fantasyland/isJust'? My reading of the spec is that it will be (and I think this should be the case), but I wanted to clarify
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API of Maybe as defined here isn't intended to be part of the specification. It could just as easily be defined as
const Just = x => n => j => j (x);
const Nothing = n => j => n;
const isJust = m => m (false) (x => true);
const fromJust = m => m () (x => x);The the definition would be:
A JavaScript value x is of type Maybe a if:
isJust(x)isfalse; orisJust(x)istrueandfromJust(x)is of typea.
Please correct me if I'm wrong on this point @davidchambers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be defined that way, but it's not. If the definition is not in the spec, how can implementers actually write compact?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any conforming library which implements compact would also have to have an implementation of Maybe. There is no requirement that it have Maybe.prototype.isJust, just that compact can tell the difference between Nothing and Just a.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gabejohnson I may be misunderstanding what you're saying, but it sounds to me like you're saying that compact can return anything it wants to represent Nothing and Just? That can't be right. What compact returns must have an isJust property. If I write code that will work with Compactable implementations from several different libraries then there needs to be a consistent way to tell the return values apart from each other. const ret = compact(a); ret.isJust === true gives me that.
The properties in the return value do not need to be prefixed since they are already inside a Fantasy Land method that is prefixed. I.e. the sole purpose of the method is to implement Compactable so returning the proper values for implementing Compactable should not be an issue.
Any conforming library which implements compact would also have to have an implementation of Maybe.
It may do that—but not necessarily. For instance, if this PR gets merged I intend to make Stream in the FRP library Hareactive implement Compactable. But Hareactive is an FRP library so it naturally does not contain a Maybe implementation. Instead the compact implementation will simply do something like this:
return somebool ? { isJust: true, value: a } : { isJust: false };
Of cause libraries that already have a Maybe implementation may want to add the isJust property to their Maybe implementation and then they could seamlessly use it in their compact implementations. That is a positive side-effect of the object representation that can give implementors an added convenience. But that can, in general, not be relied upon when working with an arbitrary compact method from an arbitrary library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that I'm not against specifying ADTs in FL, I just didn't think that's what this PR was doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that the
Maybein this PR is defined solely for the purposes of defining the behavior ofcompactand not to act as specification for an ADT.
I'd very much like us to discuss a concrete example such as this:
// Cons#fantasy-land/compact :: List (Maybe a) ~> () -> List a
Cons.prototype['fantasy-land/compact'] = function() {
return this.head.isJust ?
Cons(this.head.value, Z.compact(this.tail)) :
Z.compact(this.tail);
};Using Simon's “object encoding”, determining whether this.head is a Just simply requires accessing its isJust property. If this.head is in fact a Just we can access its inner value via the value property.
Gabe, could you show how Cons#fantasy-land/compact would be implemented using “function encoding”? The thing I don't understand is what the method would provide as the folding function to isJust. It could provide S.maybe, for example, but this would not work for all possible values of type Maybe a. What am I missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't particularly like the "function encoding", and wouldn't advocate an implementation use it. In your Cons example, compact would of course use the Sanctuary implementation of Maybe.
If we want to define an API for ADTs in FL, I think there should be a separate issue for it. It would be great for library interop and Maybe would be a good first candidate. I just think it should be in a separate PR.
The only reason I mention "function encoding" is because @puffnfresh is resistant to the idea of Fantasy Land's specifying ADTs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't particularly like the "function encoding", and wouldn't advocate an implementation use it. In your
Consexample,compactwould of course use the Sanctuary implementation ofMaybe.
Doesn't this mean that List#fantasy-land/compact would only work with Sanctuary Maybe values? This seems problematic as it introduces tight coupling between ADTs.
Perhaps #274 is not so bad after all. It gets us many of the benefits of Compactable without the problems associated with an ADT dependency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compact shouldn't return anything to represent a Maybe unless that's the Compactable it's applied to.
Oh. Yes, you are absolutely right. I had not looked at the type of compact closely enough 😅 I mistakenly thought that the Maybe was in the return type of compact and not in the arguments. I apologize for the confusion and thank you for clearing it up 👍
I don't particularly like the "function encoding", and wouldn't advocate an implementation use it.
I definitely agree.
Perhaps #274 is not so bad after all. It gets us many of the benefits of Compactable without the problems associated with an ADT dependency.
I think you may be right. In fact, the difference between them seems very small. If a structure is Filterable and a Functor then compact can be derived as
function compact(a) { return a.filter(isJust); }
So it seems that there is little difference in power.
|
Got it. I think that could be clarified
…Sent from my phone
El 1 dic 2017, a las 6:51 p. m., Gabe Johnson ***@***.***> escribió:
@gabejohnson commented on this pull request.
In README.md:
> +`Maybe a` is used in type signatures in this specification. A JavaScript value
+`x` is of type `Maybe a` if:
+
+ - `x.isJust` is `false`; or
+ - `x.isJust` is `true` and `x.value` is of type `a`.
+
+`{isJust: false}` represents `Nothing`; `{isJust: true, value: 42}` represents
+`Just 42`.
+
+### `Nothing`
+
+`Nothing` is defined as:
+
+```js
+// Nothing :: Maybe a
+const Nothing = {isJust: false};
Any conforming library which implements compact would also have to have an implementation of Maybe. There is no requirement that it have Maybe.prototype.isJust, just that compact can tell the difference between Nothing and Just a.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
|
|
This is really great work @davidchambers 👍 I think adding an abstraction that supports filter is a very worthwhile and practically useful endeavor. I think the arguments for Compactable are pretty solid. So while #274 was already really nice this PR seems even better. Naturally, I think representing the two possible return values from I must admit I had never heard of Compactable before the discussion in #274. I'll definitely be looking into it in more detail. I think a good abstraction that encompases |
|
I've been thinking this over, and I think we should just use the sum type we have ( So my vote's for #274. |
Indeed. :) |
Closes #33
This is an alternative to #274, based around
compactrather thanfilter.compactrefers toMaybe a, so this pull request defines what is meant by a value of typeMaybe a. I opted for “object encoding” as suggested by @paldepind, as it seems more idiomatic in a JavaScript setting.