-
-
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
def's signature #115
Comments
Once you learn that this object holds the type class constraints I think it becomes rather intuitive. Or at least explicit. The empty object shows us that there are no constraints on the type variables.
I think it's meant to closely resemble Hindley-Milner syntax, where the return value of the function is simply the last item in a list separated by
Actually,
I'm not sure which "curried version" you are referring to. You shouldn't pass manually curried functions such as your curried If defined via
Sanctuary's API consistently chooses positional function arguments over named arguments (with the exception of |
Thanks for the detailed response, @Avaq. Why positional arguments in this case? Let's consider some Haskell code: concat :: Semigroup a => a -> a -> a
concat x y = ... The sanctuary-def equivalent: const concat = def('concat', {a: [Semigroup]}, [a, a, a], (x, y) => ...); The function name, type-class constraints, argument types, return type, and implementation appear in the same order in both cases (except that Is there an advantage to positional arguments over a record argument in this case? Yes. Brevity. The |
@Avaq Many thanks for your clarification. I'd like to focus first on the signature issue (or the issue of my wrong understanding 😄 first):
Hm... my function is really auto-curried by
Hm... now I am puzzled. Passing the (manually) curried version of |
@davidchambers Thank you for elaborating, I see, it would probably be helpful to mention in the README at least few facts about the signature like that it aims to imitate Hindley-Milner. I am surely with both hands for brevity, but how would you support functions like |
That's right.
Actually, this is exactly the reason to curry functions in the first place: to allow more specific functions to be defined by partial application of a more general one. This is what I suggest: // defaultOpts :: FetchOptions
const defaultOpts = {...};
// fetch :: FetchOptions -> String -> Future String String
const fetch =
def('fetch',
{},
[FetchOptions, $.String, $Future($.String, $.String)],
(opts, url) => {...});
// get :: String -> Future String String
const get = fetch({method: 'GET'});
What Aldwin was saying is that the implementation provided to |
<3 this: const get = fetch({method: 'GET'}); @dmitriz take a look at: they demonstrate how data-last approach with currying is great. |
@davidchambers I see, yes, that sounds like a better and safer way. So the
Hm... if passing the curried function |
Is this not explicit?
When currying a binary function via |
I can only see it at the very beginning:
Which can be easily misread as it takes curried functions and makes them safe by enforcing the number of arguments. That is how I read it, which is apparently wrong. Something along the lines, that it actually requires a plain uncurried function, but produces its fully curried "sister" with full Ramda's functionality (if it is?) would have avoided the misunderstanding for me. Not meant as criticism (the readme is awesome otherwise), just a suggestion to improve it.
Yes, without arrow function that is more tedious indeed. I also now can see the reason behind your decision. I might not be the last one to come back asking about it though, so some sort of FAQ might smoothen it for you to have to explain it again. 😄 |
I just opened #116. Hopefully it clarifies the behaviour of |
@safareli Thanks, great links! Ironically Ramda's |
I wonder if there is any reason for choosing this signature:
https://github.com/sanctuary-js/sanctuary-def/blob/master/index.js#L62
The
{}
looks counter-intuitive (unless one goes deep into the code, of course, and reads the definitions of the variables, which, however, are not visible from the function invocation in this text aimed at the newcomers).Also putting both function arguments and return values inside a single array feels somewhat confusing as their meaning is fundamentally different. (Even mathematically, you would have to switch to duals when moving variables between source and target of a function.)
But even more importantly, the correct signature of this function seems to be
// add :: (Number, Number) -> Number,
which is not the same as the curried one above, and works differently in JavaScript.
Even worse things can happen like placing the curried version
into Ramda's
reduce
, which leads to different (and less intuitive) resultsthan its expected uncurried sister
So the question arises, which of these two signatures is reflected in this declaration:
Looking at the
def
definitionhttps://github.com/sanctuary-js/sanctuary-def/blob/master/index.js#L2346,
I wonder if there any reason not to declare it as
Then
// add :: (Number, Number) -> Number,
would become
whereas
// add :: Number -> Number -> Number,
would become
and the more complex signature
// add :: (Number -> Number) -> Number,
would become
or, the real world example
// Future :: ( a -> (), (b -> ()) -> Cancel ) -> Future a b
would become
The text was updated successfully, but these errors were encountered: