zero-functional / zero-functional

A library providing zero-cost chaining for functional abstractions in Nim.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Allow caller to change injected variable name

arnetheduck opened this issue · comments

Is there any way not to use that it name and let the caller specify instead? If not, this would make a great feature!

It's quite limiting in the sense that if you want to nest stuff, you're out of luck - likewise with any "outside" variables you might have and clash with - quite inflexible - a bit like having SQL but no JOIN. The ability to change these fixed names by editing the source does not help (imagine using the code in a medium-size project where two parts of your code want/need different names)

trivial example: x.any(y.any(y-it == x-it)) to see if there's overlap in two seqs

@arnetheduck I don't quite get your 'trivial' example - ah OK - I think I get it - but using the actual minus '-' symbol that way looks a bit exotic to me.
Also: Hm - calling any within any is maybe not what was meant to be (and any was renamed to exists because some editors consider any to be a keyword).

Currently there are two options:

  • define your own variable in the map function, e.g.
    x --> map(x_it = it)
  • rename the iteratorVariable constant in the zero_functional.nim file to whatever you wish

as to how to use the any - or exists in that case should be something like this:

x --> combinations(y) --> map((x_it, y_it) = (c.it[0], c.it[1])) --> exists(x_it == y_it)

it actually should be ((x_it, y_it) = c.it) - I'll try to fix that...

hey @michael72 - sorry for the shoddy example - x-it was to be seen as a placeholder for it-from-x. I used any because it's a common name for the operation in lots of libraries out there - missed that it happens to be called exists - weird name and weird problem.

in my eyes, perhaps more clean would be something like https://nim-lang.org/docs/sugar.html - concretely, my example code would then look like:

x.exists((a) => y.exists((b) => a == b))

likewise, if I'm happy with the it name sometimes, I could go with:

x.exists((a) => y.exists(a == it))

while the code you provide gets the job done, it's not.. elegant / something I'd use really

@arnetheduck
why on earth is exists a weird name?! AFAIK it has always been called exists in mathematical contexts - there is even a symbol for that.
In C#, F# and scala it is named exists, not any. Surely also in some more mathematical languages.
Also: see definition of any in nim

So to me it is weird, that someone would name something any what rightfully should be named exists.
Also look at the nice syntax highlighting most editors do - this one included and compare:

a --> exists(it == 2)
a --> any(it == 2)

Oh - it is red - why is it red - don't know - but looks funny. Or should I say weird?

As for the rest - I see what you mean - I'll have a look. Not sure if that is feasible right now.

I agree, any vs exists is bikeshedding, we should keep exists.

The x.exists((a) => y.exists((b) => a == b)) seems useful tho

Oh for sure, I'm not suggesting changing to any, just didn't expect it as I mostly come from a different lang background :) ie it's called variations on any in c++, nim, haskell and python, for example

@arnetheduck / @alehander42
the actual syntax here is --> and stays that way and not =>
So I did a little bugfixing - now it would be possible to write something like:

    let x = @[1,2,3]
    let y = @[2,5,6]
    check(x --> map(a = it) --> exists(y --> exists(a == it)))
    # shortcut syntax: (a) will be translated to map(a = it), this also works for (a,b), ...
    check(x --> (a) --> exists(y --> exists(a == it)))

@arnetheduck
If you want to use it, please have a look at the documentation and the examples. Especially the syntax! Thanks.

... OK I thought again a little about it but

  • we are using macros for the most part - we do not really have any exists function - so writing x.exists(...) here is out of the question
  • using => from sugar module or not from sugar - could be useful - but comparing
x --> exists((a) => y --> exists((b) => a == b)

and

x --> (a) --> exists(y --> (b) --> exists(a == b))

I don't know which one is more readable or more confusing....
In the => case it is not clear to me that (a) is the actual iterator of x whereas in the latter one that maybe is a bit clearer, maybe not necessarily that a replaces it - but this is the current working solution for the shortcut.
So I could change the shortcut to something like

x --> a = it --> exists(y --> b = it --> exists(a == b))

or (if that is synstactically possible)
update: this is syntactically possible, but not semantically (undeclared identifer a / it).

x(a = it) --> exists(y(b = it) --> exists(a == b))
x(a) --> exists(y(b) --> exists(a == b))

hum or

(x --> a) --> exists((y --> b) --> exists(a == b))

update: this could be hard to implement - context of exists has to be put below the definition in (x --> a) so to say. I'll have a look but doubt that it's feasible.
@alehander42 what do you think?

So - basically I implemented 2 alternatives now:

(x --> it_x) --> exists((y --> it_y) --> exists(it_x == it_y))

and

x --> (it_x) --> exists(y --> (it_y) --> exists(it_x == it_y))

Extra use of => would have to be implemented as a macro but would collide with sugar's =>.
Possible alternative call syntax also does not work out.

So - basically this is my solution.