question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

I wonder if there is any reason for choosing this signature: https://github.com/sanctuary-js/sanctuary-def/blob/master/index.js#L62

//    add :: Number -> Number -> Number

def('add', {}, [$.Number, $.Number, $.Number], (x, y) => x + y);

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

const add = x => y => x + y

into Ramda’s reduce, which leads to different (and less intuitive) results than its expected uncurried sister

const add = (x, y) => x + y

So the question arises, which of these two signatures is reflected in this declaration:

def('add', {}, [$.Number, $.Number, $.Number], (x, y) => x + y);

Looking at the def definition https://github.com/sanctuary-js/sanctuary-def/blob/master/index.js#L2346, I wonder if there any reason not to declare it as

function def({name, constraints, type, impl}) { ...

Then

//   add :: (Number, Number) -> Number,

would become

def({
    name: 'add', 
    type: $.Function([$.Number, $.Number], $.Number),
    impl: (x, y) => x + y
})

whereas

//   add :: Number -> Number -> Number,

would become

def({
    name: 'add', 
    type: $.Function($.Number, $.Function($.Number, $.Number)), 
    impl: (x, y) => x + y
})

and the more complex signature

//   add :: (Number -> Number) -> Number,

would become

def({
    name: 'eval', 
    type: $.Function($.Function($.Number, $.Number)),
    target: $.Number, 
    impl: (f, x) => f(x)
})

or, the real world example

//   Future :: ( a -> (), (b -> ()) -> Cancel ) -> Future a b

would become

def({
    name: 'Future', 
    type: $.Function($.Function(A, $.Empty), $.Function($.Function(B, $.Empty), Cancel), Future A B)),
    impl: (x, y) => x + y
})

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:11 (6 by maintainers)

github_iconTop GitHub Comments

3reactions
Avaqcommented, Dec 28, 2016

The {} looks counter-intuitive

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.

putting both function arguments and return values inside a single array feels somewhat confusing

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 ->.

the correct signature of this function seems to be add :: (Number, Number) -> Number

Actually, def also curries the “implementation”. So Number -> Number -> Number is correct. The fact that it’s also possible to call it by passing multiple arguments at once is kind of like a “syntactic sugar” to make it less painful to apply multiple arguments with JavaScript.

Even worse things can happen like placing the curried version into Ramda’s reduce

I’m not sure which “curried version” you are referring to. You shouldn’t pass manually curried functions such as your curried add into def, as def will fail to call them properly (assuming that’s what you mean?).

If defined via def correctly, a function can be safely treated as either curried or uncurried. It should therefore be safe to pass it into functions like Ramda’s reduce (which expects (a, b) -> a) or Sanctuary’s reduce (which expects a -> b -> a).

I wonder if there any reason not to declare it as function def({name, constraints, type, impl}) { ...

Sanctuary’s API consistently chooses positional function arguments over named arguments (with the exception of create, after some debate). It’s a preference of @davidchambers, I believe. It also makes it easier to curry these functions, since “named arguments” is really just a single argument of an object with mixed value types.

1reaction
safarelicommented, Dec 29, 2016

❤️ this:

const get = fetch({method: 'GET'});

@dmitriz take a look at:

they demonstrate how data-last approach with currying is great.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Signature Definition & Meaning - Dictionary.com
a person's name, or a mark representing it, as signed personally or by deputy, as in subscribing a letter or other document. ·...
Read more >
Signature definition and meaning | Collins English Dictionary
1. a person's name, or a mark representing it, as signed personally or by deputy, as in subscribing a letter or other document...
Read more >
SIGNATURE | definition in the Cambridge English Dictionary
your name written in the particular way you write it, esp. on a printed document to show that you have written it yourself:...
Read more >
Signature Definition & Meaning | Britannica Dictionary
SIGNATURE meaning: 1 : a person's name written in that person's handwriting; 2 : the act of signing something.
Read more >
Signature - Definition, Meaning & Synonyms | Vocabulary.com
signature Add to list Share · noun. your name written in your own handwriting · noun. a distinguishing style · noun. a melody...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found