Skip to content

Conversation

@davidchambers
Copy link
Member

Closes #33

This is an alternative to #274, based around compact rather than filter. compact refers to Maybe a, so this pull request defines what is meant by a value of type Maybe a. I opted for “object encoding” as suggested by @paldepind, as it seems more idiomatic in a JavaScript setting.

@Fresheyeball
Copy link

Fresheyeball commented Nov 30, 2017

Good job! Find throwing me a mention for this?

@davidchambers
Copy link
Member Author

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};
Copy link
Contributor

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

Copy link
Member

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) is false; or
  • isJust(x) is true and fromJust(x) is of type a.

Please correct me if I'm wrong on this point @davidchambers

Copy link
Contributor

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?

Copy link
Member

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.

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.

Copy link
Member

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.

Copy link
Member Author

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 Maybe in this PR is defined solely for the purposes of defining the behavior of compact and 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?

Copy link
Member

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.

Copy link
Member Author

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.

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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabejohnson

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.

@davidchambers

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.

@rjmk
Copy link
Contributor

rjmk commented Dec 1, 2017 via email

@paldepind
Copy link

paldepind commented Dec 6, 2017

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 compact with an object is a good choice 😉 It is very natural and easy to work with in JavaScript.

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 filter has been much needed.

@gabejohnson
Copy link
Member

I've been thinking this over, and I think we should just use the sum type we have (Boolean). Introducing types to the spec should probably be done in a separate PR. We can always revisit Compactable if Maybe is added to the spec.

So my vote's for #274.

@davidchambers
Copy link
Member Author

We can always revisit Compactable if Maybe is added to the spec.

Indeed. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants