h3rald / min

A small but practical concatenative programming language and shell
https://min-lang.org
MIT License
311 stars 23 forks source link

Find with multiple predicates & quote-define #15

Closed mwgkgk closed 6 years ago

mwgkgk commented 6 years ago

Trying to use find like this:

(1 'hello 3) ('hello ==) find

Fails with [==]: Two non-symbol values of similar type are required on the stack. (Which is probably a usecase in it's own - to have a scheme-like hierarchy of eq? eqv? equal? with more-permissive and less-permissive variants).

Trying to safeguard this with quotation?, I cannot figure out a way to apply multiple predicates, because quotation? just executes and puts it's result on the stack, and we have nothing left to check against. Trying to quote-define the argument for reuse like this:

(1 'hello 3) (#item item quotation?) find

Results in [bind]: Attempting to bind undefined symbol: item. In general I couldn't get quote-define to work even in the form it's seen in tutorial:

(1 2 3 4 5) #my-list

Using the github version of Min.

Thank you for your time <3

mwgkgk commented 6 years ago

Was able to work around it with dup:

 (1 'hello 3) (dup quotation? quote ('hello ==) (false) if) find

Leaving the issue open because quote-define is probably bugged.

mwgkgk commented 6 years ago

The above solution is polluting the stack! Which also causes the code in first quotation to execute if we go into the (false) branch. So it's not a good workaround.

h3rald commented 6 years ago

Hi again!

Yes, I’ll look into adding more permissive predicates to cover those use cases as well, it makes sense.

Concerning quote-define... There is a bug in the docs! # is the sigil for quote-bind while for quote-define you have to use =.

mwgkgk commented 6 years ago

More info:

  ("hello" puts!) "a" =

Fails with [=]: Undefined symbol '=', despite it being defined in the source:

  def.sigil("=") do (i: In):
    i.push("quote-define".newSym)

This works:

  ("hello" puts!) "a" quote-define
h3rald commented 6 years ago

OK so for now:

mwgkgk commented 6 years ago

Beautiful!

One more question on comparisons: how to safely find a function in a quote?

("hello" puts!) :experiment
(1 2 3 experiment) (quote 'experiment ==) find

The predicate function above starts with quote because unquoted experiment is not equal to 'experiment. The problem is though that find is executing experiment (by placing it on stack?) before the predicate comes into play. Same issue with reduce.

h3rald commented 6 years ago

Actually it turns out that all the predicates leave the element on the stack! Now, from the docs they should remove it after checking, so I am going to consider it a bug and change their behavior.

Also, I am planning on adding two new logical operators to allow short-circuiting: dequote-and and dequote-or, so you’ll be able to write things like this:

  (1 8 “a” 3 “b” 4 5 6) (:x (x number?) (x 5 <) dequote-and) filter
  # returns (1 3 4)

...without having to wrap checks in an if or when.

mwgkgk commented 6 years ago

I'm not sure if that's going to help with my find usecase, because the evaluation of the experiment there happens before the predicate gets evaluated, so it has nothing to compare against.

string? quotation? etc are indeed leaving the element on stack and push the boolean after it, my bad for not realizing the behavior was uninteded - because signatures in the docs clearly don't match. I used to work around it with nip.

h3rald commented 6 years ago

Your original use case now works with ==:

  (1 2 ‘test ‘hello 4 5) (‘hello ==) find 
  # returns 3

No need for the quotation? check anymore in this case.

mwgkgk commented 6 years ago

Problem is the symbol in array is a function call:

(1 2 3 experiment)

Rather than a quoted symbol:

(1 2 3 'experiment)

What I'm doing is parsing the source of a function. So it has actual calls rather than quoted calls

h3rald commented 6 years ago

Ahh ok got it. I could introduce a new quote-map symbol to quote the elements of a quotation without evaluating them... so you could write the following:

  (2 3 + 4 *) quote-map  (‘+ ==) find

Any better idea?

mwgkgk commented 6 years ago

This is an elegant solution: no find's, reduce's and who-knows-what-else's need to be touched.