-
-
Notifications
You must be signed in to change notification settings - Fork 95
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
abandon Ramda-style currying in favour of simple currying #520
Conversation
That is a pretty daunting diff. Most seem like stylistic changes of sorts, eg |
I agree. I am reviewing the changes myself and don't know where to focus my attention. I'll post comments on some sections which strike me as potentially controversial. :) |
}, | ||
}, | ||
], | ||
}; |
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.
This file allows us to verify that doctests and code snippets follow our desired formatting rules.
'CallExpression > ArrowFunctionExpression ArrowFunctionExpression > *', | ||
'CallExpression > FunctionExpression > BlockStatement' | ||
); | ||
module.exports = indent; |
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.
ESLint does not like this indentation:
f (x)
(y)
(z)
Rather than disable the indent
rule entirely, we can add exceptions for problematic cases.
cp README.md README.md.temp | ||
rewrite <README.md.temp >README.md | ||
|
||
node_modules/.bin/eslint --config eslint/es6.js -- README.md eslint |
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.
This script enables npm run lint
to run eslint
on files that would not otherwise be linted.
Linting the readme involves a number of steps:
- Save a copy of the file as it exists.
- Regenerate the readme (the
VERSION
andPREVIOUS_VERSION
values are unimportant). - Use
rewrite
to remove leading>
and.
characters, parenthesize object literals which would otherwise be parsed as blocks, and insert a semicolon at the end of each input and output line. - Run
eslint
. - Restore the readme to its original state (via an EXIT trap).
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.
assert.strictEqual (arguments.length, eq$1.length); | ||
assert.strictEqual (toString (actual), toString (expected)); | ||
assert.strictEqual (equals (actual) (expected), true); | ||
}; | ||
}; |
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 internal eq
function is now curried.
return function throws$1(expected) { | ||
assert.strictEqual (arguments.length, throws$1.length); | ||
assert.throws (thunk, equals (expected)); | ||
}; | ||
}; |
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 internal throws
function is now curried, and now takes a single value representing the expected error rather than a type representative and an error message.
Before:
throws(thunk, TypeError, 'Invalid value');
After:
throws (thunk) (new TypeError ('InvalidValue'));
return function Cons$1(tail) { | ||
eq (arguments.length) (Cons$1.length); | ||
return new _List ('Cons', head, tail); | ||
}; | ||
}; |
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.
Cons
is now curried.
return function(y) { | ||
return $.Function ([x, y]); | ||
}; | ||
} |
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.
Fn
is now curried.
(readmeUrl ('EitherType')) | ||
(typeEq (eitherTypeIdent)) | ||
(either (of (Array)) (K ([]))) | ||
(either (K ([])) (of (Array))); |
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.
Now that functions such as K
are curried (and hoisted) we're able to use them throughout the file. :)
//. | ||
//. Returns `true` [iff][] the *second* argument is less than the first | ||
//. according to [`Z.lt`][]. The arguments must be provided one at a time. | ||
//. according to [`Z.lt`][]. |
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.
This is one of the important changes listed in #438 (comment). Now that all functions are “simply” curried there's no reason for this function's type to be [a, $.Predicate (a)]
rather than [a, a, $.Boolean]
. :)
return function(filterable) { | ||
return Z.filter (pred, filterable); | ||
}; | ||
} |
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.
We are defining filter
rather than setting impl
to curry2 (Z.filter)
in order to partially apply the function in other definitions.
}; | ||
function step(next, done, x) { | ||
return Z.map (either (next) (done), f (x)); | ||
} |
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 decided to rely on function hoisting here to avoid interrupting the function > return > > return
staircase.
return function(x) { | ||
return function(y) { | ||
return function(z) { | ||
return f (v, w, x, y, z); |
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.
For some reason this makes me happy. :D
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 was typing a similar comment to curry
:
So blissfully transparent! :D
...but then I scrolled down and saw curry2
, which made me happier, so I removed the comment to move it over there. But then I scrolled down further to find curry3
. Woah, how cool is this going to get? I scrolled all the way to curry5
and found your comment. :)
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.
🤣
@@ -1711,7 +1773,7 @@ | |||
//. > S.Nothing.isNothing | |||
//. true | |||
//. | |||
//. > S.Just(42).isNothing | |||
//. > (S.Just (42)).isNothing |
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.
This is a situation in which unnecessary parens are justified: isNothing
in S.Just (42).isNothing
is tightly bound, visually, to 42
.
Fortunately, such property access is rare in code written with Sanctuary (one could use S.isNothing
in this case).
//. 'Just([1, 2, 3])' | ||
//. ``` | ||
Maybe.prototype.toString = function() { | ||
return this.isJust ? 'Just(' + Z.toString(this.value) + ')' : 'Nothing'; | ||
return this.isJust ? 'Just(' + Z.toString (this.value) + ')' : 'Nothing'; |
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.
At some point I would like to switch from 'Just(42)'
to 'Just (42)'
, but doing so now would lead to inconsistencies such as 'Just (new Date(0))'
. This order would be optimal, I believe:
- Create sanctuary-show, copying the
Z.toString
implementation but usingf (x)
style. - Update sanctuary-maybe to depend on sanctuary-show, and replace
Maybe#toString
withMaybe#@@show
which usesf (x)
style. - Update this project to depend on sanctuary-maybe and sanctuary-show, and replace
S.toString
withS.show
.
function maybe(x) { | ||
return function(f) { | ||
return function(maybe) { | ||
return maybe.isJust ? f (maybe.value) : x; |
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 feels right to define fromMaybe
in terms of maybe
rather than the other way around.
index.js
Outdated
types: [Fn(a, $Maybe(b)), f(a), f(b)], | ||
impl: mapMaybe | ||
types: [Fn (a) ($Maybe (b)), f (a), f (b)], | ||
impl: blackbird (justs) (map) |
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.
Using blackbird
may be a step too far. ;)
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 would think so. Especially if used sparsely and considering that the definition of blackbird itself is also somewhat mind-bending.
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.
Now that I've figured out what's going on, I also see the appeal though ;)
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've removed blackbird
. The implementation is now B (B (justs)) (map)
.
The implementations of encase2
and encase3
sell me on the idea:
B (B (B (eitherToMaybe))) (encaseEither2 (I))
B (B (B (B (eitherToMaybe)))) (encaseEither3 (I))
Beautiful!
On several occasions I've defended map (map (map (map (nbsp))))
. I feel a similar way about B (B (B (B (eitherToMaybe))))
. It looks strange at first, but once one learns how to interpret the nesting it's much clearer than the equivalent nested lambdas.
index.js
Outdated
types: [$.Predicate(a), a, $.Boolean], | ||
impl: complement | ||
types: [$.Predicate (a), a, $.Boolean], | ||
impl: compose (not) |
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.
Curried compose
is very useful!
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 have been saying the same thing! This is one of the reasons why Ramda's compose is so crippled, but you don't really realise until you try it.
impl: find | ||
}; | ||
|
||
//# unfoldr :: (b -> Maybe (Pair a b)) -> b -> Array a | ||
//# unfoldr :: (b -> Maybe (Array2 a b)) -> b -> Array 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.
We're now using $.Array2
, which replaced $.Pair
.
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 would be interested to find out how these changes affect performance. I would imagine JavaScript function context creation time has increased quite a lot.
4d8d321
to
359240f
Compare
That would be fascinating to see benchmarks, ideally of actual projects (not just adding a bunch of numbers) |
Closes #438
https://github.com/sanctuary-js/sanctuary-def/releases/tag/v0.15.0