Skip to content
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

Sanctuary >0.15.0 compatibility and general improvements #8

Merged
merged 7 commits into from
Oct 8, 2018

Conversation

Gipphe
Copy link
Contributor

@Gipphe Gipphe commented Oct 5, 2018

Summary:

  • sanctuary-def must be passed to create in the configuration object.
  • All defined functions, as well as all type constructors, must be manually curried, or otherwise support currying.
  • Update babel to version 7.
  • Update chai and mocha.
  • Replace ramda with sanctuary and some single-function packages.
  • Replace ramda-fantasy's Reader with own implementation that is fantasy-land compatible.
  • Update eslint-config-airbnb-base to 13.1.0, updating its peer dependencies to match.

Closes #7

src/Reader.js Outdated
Reader.ask = Reader (S.I);

Reader.prototype.toString = Reader.prototype[$$show] = function show_() {
return 'Reader(' + show (this.run) + ')';
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we use Reader (...) to match Sanctuary style?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean add a space between Reader and the opening parens?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be more specific, change it to Reader (' + show (this.run) + ')';?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Call be impatient, but I just made the change I assumed you meant.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

@Gipphe Gipphe force-pushed the master branch 3 times, most recently from 00f7707 to cc4129f Compare October 5, 2018 11:53
@Gipphe
Copy link
Contributor Author

Gipphe commented Oct 5, 2018

Added tests for Reader. Forgot all about those for Reader in particular, initially. Sorry about the repeated "Gipphe added some commits" with the rebases.

@nkrkv
Copy link
Member

nkrkv commented Oct 5, 2018

I suggest bumping version to 4.0.0 in package.json (will publish immediately after the merge). Also, a short note about the changes in the “Changelog” section of README.md is much desired.

@davidchambers
Copy link
Contributor

I suggest bumping version to 4.0.0 in package.json (will publish immediately after the merge).

This should be part of an automated release process. Would you like me to submit a pull request to integrate xyz?

@evgenykochetkov
Copy link
Contributor

evgenykochetkov commented Oct 5, 2018

While testing this on XOD codebase, I found an interesting thing about HOFs that deal with functions with 2+ arguments.

We parse ... -> (String -> Number -> Boolean) -> ... as ..., $.Function ([$.String, $.Number, $.Boolean]), ...:

const {types} = resolve ($) ([]) ($.env) ('foo :: String -> (String -> Number -> Boolean) -> String');
const lists = S.zip (types) ([$.String, $.Function ([$.String, $.Number, $.Boolean]), $.String]);
assertTypePairs (lists); // passes

But since $.Function behaviour did not change from >0.15 (sanctuary-js/sanctuary-def#179 (comment)) it is turned into something like ... -> ((String, Number) -> Boolean) -> ...:

const signature = 'foo :: a -> (a -> a -> Boolean) -> a';

const foo = def
  (signature)
  (() => 'implementation does not matter for this example');

assert.equal (foo.toString (), signature);
// + expected - actual
// -foo :: a -> ((a, a) -> Boolean) -> a
// +foo :: a -> (a -> a -> Boolean) -> a

@Gipphe
Copy link
Contributor Author

Gipphe commented Oct 5, 2018

@evgenykochetkov

But since $.Function behaviour did not change from >0.15 (sanctuary-js/sanctuary-def#179 (comment)) it is turned into something like ... -> ((String, Number) -> Boolean) -> ...:

const signature = 'foo :: a -> (a -> a -> Boolean) -> a';

const foo = def
  (signature)
  (() => 'implementation does not matter for this example');

assert.equal (foo.toString (), signature);
// + expected - actual
// -foo :: a -> ((a, a) -> Boolean) -> a
// +foo :: a -> (a -> a -> Boolean) -> a

Forgot about how $.Function types out a non-curried function... Meaning (a -> b -> c) -> d should be

[$.Function ([a, $.Function ([b, c])]), d]

instead of

[$.Function ([a, b, c]), d]

Shouldn't be that hard (right?)

@nkrkv
Copy link
Member

nkrkv commented Oct 5, 2018

Would you like me to submit a pull request to integrate xyz?

Yes, that would be very nice.

In this case, @Gipphe, please do not bump the version

@evgenykochetkov
Copy link
Contributor

Forgot about how $.Function types out a non-curried function... Meaning (a -> b -> c) -> d should be

[$.Function ([a, $.Function ([b, c])]), d]

instead of

[$.Function ([a, b, c]), d]

Yes

@Gipphe
Copy link
Contributor Author

Gipphe commented Oct 5, 2018

@evgenykochetkov Done.

@Gipphe
Copy link
Contributor Author

Gipphe commented Oct 5, 2018

It now supports type signatures like foo :: (a -> b -> c) -> d as well as bar :: a -> (b -> c -> d) as you'd expect.

src/signature.js Outdated Show resolved Hide resolved
src/signature.js Outdated Show resolved Hide resolved
src/signature.js Outdated
const firstChild = S.pipe ([
children,
S.head,
unchecked.fromMaybe (undefined),
Copy link
Contributor

Choose a reason for hiding this comment

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

Why return undefined rather than S.Nothing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At the time I wrote this function, I cared more to copy the dependent-upon behavior of R.compose(R.head, children), which was the previous implementation. Now that tests are passing, I can safely redo it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, this function will never receive an object that has an empty children property, so we can go even simpler and do with xs => xs[0].

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good. You should update the type signature accordingly:

-// firstChild :: { children :: Array a } -> a
+// firstChild :: { children :: NonEmpty (Array a) } -> a

I think this is the clearest implementation:

const firstChild = r => r.children[0];

I also suggest aligning the type signature with the identifier on the subsequent line:

//    firstChild :: { children :: NonEmpty (Array a) } -> a
const firstChild = r => r.children[0];

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to update a lot of the type signatures I see now, upon further inspection. This little function's isn't the only one. Aligning the type signatures is a bit of a minor thing, but I am inclined to agree that it looks better that way.

src/signature.js Outdated Show resolved Hide resolved
@Gipphe Gipphe force-pushed the master branch 4 times, most recently from 0f6d17d to 50a505b Compare October 5, 2018 23:34
@Gipphe
Copy link
Contributor Author

Gipphe commented Oct 5, 2018

There are a lot of S.unchecked uses throughout signature.js, mostly because sanctuary extracts the type of Reader incorrectly. This could be remedied by actually defining a type for Reader, which we then pass to sanctuary's create. Or, and this is a question aimed more at @nkrkv, the original author: why are we using Reader at all? I haven't been around in the FP world long enough to see all the benefits a monad like Reader might bring to the table, so please do enlighten me if I am missing something obvious.

@nkrkv
Copy link
Member

nkrkv commented Oct 8, 2018

Or, and this is a question aimed more at @nkrkv, the original author: why are we using Reader at all

I used it at the peak of my craziness while getting familiar with FP on practice. It is actually an over-engineering legacy. It is absolutely OK to get rid of it.

@Gipphe
Copy link
Contributor Author

Gipphe commented Oct 8, 2018

I used it at the peak of my craziness while getting familiar with FP on practice. It is actually an over-engineering legacy. It is absolutely OK to get rid of it.

Am still struggling with over-engineering myself, so I feel ya.

@Gipphe Gipphe reopened this Oct 8, 2018
BREAKING CHANGE: no longer works with regular multi-arity function
application. Requires functions to be curried, either manually or with
the help of functions like `ramda`'s `curry` and `curryN`, or
`sanctuary`'s own curry helpers, `curry2`-`curry5`.
Multi-arity higher order functions are types as
```javascript
[
  $.Function ([
    a,
    $.Function ([
      b,
      c
    ]),
  ]),
  d
]
```
instead of
```javascript
[
  $.Function ([
    a,
    b,
    c
  ]),
  d
]
```
Copy link
Member

@nkrkv nkrkv left a comment

Choose a reason for hiding this comment

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

👍

@nkrkv nkrkv merged commit 81bec3e into xodio:master Oct 8, 2018
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.

4 participants