-
-
Notifications
You must be signed in to change notification settings - Fork 24
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 #179
Conversation
index.js
Outdated
@@ -58,23 +58,23 @@ | |||
//. | |||
//. ```javascript | |||
//. // env :: Array Type | |||
//. const env = $.env.concat([List($.Unknown)]); | |||
//. const env = $.env .concat ([List ($.Unknown)]); |
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.
Inconsistency: Space preceding .concat
but not .env
.
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 space after the method name is to appease the linter. If we want to write f (x)
the linter wants us to write foo.bar (baz)
as well. I was experimenting with surrounding method names with spaces to make them appear more like infix operators: xs .concat (ys)
. What do you think?
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 see a :thumbsdown:
from Gabe. I certainly don't love the proposal. Let's vote!
- 😆
$.env.concat([List ($.Unknown)])
✘ - 🎉
$.env.concat ([List ($.Unknown)])
✔︎ - ❤️
$.env .concat ([List ($.Unknown)])
✔︎
The ✔︎/✘ indicates whether we'll be able to continue to use func-call-spacing
.
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 like the idea of the formatting as a signal that curried functions are being used.
[1, 2, 3].concat([4, 5, 6]); // Nothing special going on here
S.concat ([1, 2, 3]) ([4, 5, 6]); // FP in the house!
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 can see the logic behind that, Gabe. What about unary functions, though? Math.abs(x)
or Math.abs (x)
? S.trim(s)
or S.trim (s)
?
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.
What about require('express')(b, c)
? What about fs.reduce(f, x)(y)
? I think trying to categorise function calls based on underlying structure will raise more questions than it settles. I vote for the consistency of always putting a space between the function or method identifier and its application:
Math.abs (x)
require ('express') (a, b)
fs.reduce (f, x) (y)
$.env.concat ([List ($.Unknown)])
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.
f(x)(y).z
is problematic. In f (x) (y).z
the .z
property access appears to be bound to (y)
rather than to f (x) (y)
. There are two reasonable solutions, each of which violates one of our current rules:
f (x) (y) .z
(violatesno-whitespace-before-property
)(f (x) (y)).z
(violatesno-extra-parens
)
I prefer the latter as it is consistent with foo.bar.baz
(I'm not ready to switch to foo .bar .baz
).
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.
So with this new approach, all preceding occurrences of Z.env .concat
can be fixed, right?
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.
⚡
@@ -402,6 +393,10 @@ | |||
var Inconsistent = | |||
new _Type(INCONSISTENT, '', '', always2('???'), K(false), [], {}); | |||
|
|||
// NoArguments :: Type | |||
var NoArguments = | |||
new _Type(NO_ARGUMENTS, '', '', always2('()'), K(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.
If I understand correctly what this is for, we could consider naming it Unit
, right?
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.
NoArguments
and Unit
represent related but distinct ideas.
Were we to define const Unit = {};
and the accompanying Type value, f ()
and f (Unit)
would still be different expressions: one applies f
to no arguments; the other applies f
to one argument.
It could be confusing to name the above Type value Unit
as we may one day wish to define a Type value equivalent to Haskell's ()
. This would logically be named Unit
.
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.
In Haskell ()
is a nullary tuple. I like to think that the only differences between Haskell and JavaScript, are that JavaScript forces you to pattern-match your tuples, and you can only instantiate them at call time.
// f :: Tuple a b -> c -> ...
// -- alernatively written as
// f :: (a, b) -> c -> ...
const f = (a, b) => c => ...
When viewing it like this, Unit has no addressable value level member (only at call time).
//. type; and | ||
//. - `$.Function([a, b, a])` represents the `(a, b) -> a` type. | ||
function Function_(types) { | ||
//. - `$.Function ([a, b, a])` represents the `(a, b) -> a` type. |
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.
Does it still?
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.
Yes. The behaviour of $.Function
is unchanged. I believe sanctuary-def should be capable of expressing types of which we disapprove. ;)
index.js
Outdated
function NullaryType(name) { | ||
return function(url) { | ||
return function(test) { | ||
function format(outer, inner) { |
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 looks like the format
function could be shared between different applications of NullaryType (name)
.
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.
Great point! I'll address this.
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.
⚡
return function(test) { | ||
return function(_1) { | ||
return function($1) { | ||
function format(outer, inner) { |
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.
ditto
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 function references $1
.
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.
Oh, I missed that.
return function(_2) { | ||
return function($1) { | ||
return function($2) { | ||
function format(outer, inner) { |
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.
ditto
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 function references $1
and $2
.
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.
Oh, I missed that.
return new _Type(VARIABLE, name, '', format, K(true), keys, types); | ||
return function($1) { | ||
return function($2) { | ||
function format(outer, inner) { |
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.
ditto
index.js
Outdated
} | ||
|
||
// fromUncheckedBinaryType :: ((Type, Type) -> Type) -> | ||
// fromUncheckedBinaryType :: (Type -> Type -> Type) -> | ||
// (Type -> Type -> Type) |
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.
Brackets for clarity?
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.
⚡
([a, a, a, $.Array (a)]) | ||
(x => y => z => [x, y, z]); | ||
|
||
// $26 :: a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> 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.
Haha
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 wanted to show that we're no longer limited to nine parameters. 😂
test/index.js
Outdated
}); | ||
// eq :: (a, b) -> Undefined ! | ||
function eq(actual, expected) { | ||
assert.strictEqual (arguments.length, eq.length); |
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.
Curious that you use the new style in the examples and the tests, but not the actual source.
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 can imagine reformatting the source code too, but I'd prefer to do so in a separate pull request to avoid obfuscating the significant code changes.
2b72b37
to
e16c7b0
Compare
index.js
Outdated
} else { | ||
indexes.push(index); | ||
return function(x) { | ||
var args = slice.call(arguments); |
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 think we might be able to avoid calling slice.call
here. It would increase performance.
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.
Great point!
⚡
} | ||
|
||
var isThunk = expType.types.$1.type.type === NO_ARGUMENTS; | ||
var numArgsExpected = isThunk ? 0 : expType.keys.length - 1; |
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 to self: I want to think about this approach.
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 thoughts: #180
index.js
Outdated
vReprs.push(Z.toString(_values[idx])); | ||
var wrapped = typeInfo.types[0].type === NO_ARGUMENTS ? | ||
function() { | ||
var args = slice.call(arguments); |
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.
Same here. We can move the slice.call
part to the unhappy path.
d960c05
to
9997c9c
Compare
I've rebased this pull request now that #184 has been merged. Please review scripts/lint and .eslint-es6.js. |
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.
Looks good to me!
2e6779f
to
51ff546
Compare
‘def’ has served two roles: - currying an uncurried implementation function; and - performing type checking at run time. At the time of this project's inception in 2015 it seemed unreasonable to require users to provide curried implementation functions. Defining curried functions manually was onerous prior to ES6: function(x) { return function(y) { return function(z) { return ...; }; }; } With ES6, defining curried functions is trivial: x => y => z => ... The landscape has changed since 2015, and it's now reasonable to assume that users are targeting ES6. Furthermore, the advantages of Ramda-style currying over simple currying do not justify the additional complexity. There's no compelling reason for ‘def’ to continue to serve two roles. User-facing changes: - ‘$’ functions must now be applied to arguments one at a time; - ‘def’ now requires a curried implementation function; - ‘def’ no longer imposes an arbitrary arity limit; - ‘def’ functions must now be applied to arguments one at a time; and - ‘__’ has been removed (simple currying precludes placeholders). Internal changes: - the ‘checkTypes’ option is now checked in just one place; and - ‘def’ is now essentially a no-op if type checking is disabled.
51ff546
to
48529ee
Compare
Commit message:
This pull request embraces the
f (x) (y)
style proposed in sanctuary-js/sanctuary#438.The changes to the test suite will be easier to review once #178 has been merged.