bakpakin / Fennel

Lua Lisp Language
https://fennel-lang.org
MIT License
2.42k stars 124 forks source link

`case` documentation #434

Closed rktjmp closed 1 year ago

andreyorst commented 1 year ago

I feel like a more elaborate explanation of the distinction between case and match is needed, because case macro that skips unification doesn't explain much. Though the original match explanation wasn't really clear on that part too.

rktjmp commented 1 year ago

Yep, haven't quite gotten to match yet. Unsure whether to introduce the term unification or call it implicit pinning, or instead term pin as unify in case...

I don't think pin is immediately obvious to a new reader, but I think unification might also imply more mechanics. It's more like references or tie (maybe not tie...).

Ideally there would be one term, unify operator unification or pin operator pinning or ... I only call it pin because I have seen it in Elixir, not sure of other prior art - that might help get the right (or at least traditional) name.

andreyorst commented 1 year ago

A bit off-topic, but, I've been looking at where, and in reality, where actually acts almost like and, with the exception that it only accepts two arguments, the first being the pattern, and the last being the clause.

Maybe we could lift this and allow multiple patterns/clauses and rename it to and? As far as I understand we'll get plain or in match soon, so it will play nicely. @technomancy WDYT?

rktjmp commented 1 year ago

Maybe we could lift this and allow multiple patterns/clauses and rename it to and?

Discarding or for a moment, multiple patterns and clauses, or a pattern and multiple clauses? I assume you could only give multiple patterns with or.

ex:

A case clause accepts multiple patterns in an or form. or must contain at least one pattern, as described in the preceeding section.

(case x
  (or 1 2 3) true ; x was 1 2 or 3
  _ false)
(case x
  (or 1) :valid
  (or y) :valid
  (or (v-1 v-2) [(= key)]) :valid
  (or) :invalid
  _ false)

case clauses may also optionally be "guarded" with an and form. The first value/form/expression/argument provided to and must be a pattern or collection of patterns as described by or above. Each additional expression represents a guard. All guard expressions must evaluate to truethy for the case clause to match.

Guard expressions may contain any valid Fennel code and have access to any in-scope binding.

(case x
  (and (or 1 2 3) (sunday? today)) true ; 1 2 or 3 on a sunday
  ;; 1 2 or 3 in a leap year and we rolled lucky
  ;; note that the second `and` is a regular boolean expression
  (and (or 1 2 3) (and (leap-year? today) (feeling-lucky?))) true
  true :ok
  _ false)
(case x
  (and 1) :valid ;; (and 1 true) but I think worth supporting
                 ;; for easy of modification when writing code.
  (and (or (= x))) :valid
  (and {:count c :name (= user-name)} (and (<= limit c)
                                           (authorised? user-name))) :valid
  (and) :invalid
  (and (or))) :invalid

I think there might be some clarity of intent lost by overloading the terms and and or but they do still behave as their regular counter parts, just with some restrictions on what values can go where which can be pointed out with a compiler warning pretty clearly?

technomancy commented 1 year ago

Thank you for this thorough patch!

I have some suggestions inline; please let me know what you think. My understanding of how the term unification is used has changed since I did a bit of research, and I now favor the term "pinning" for how we were using "unification" previously.

I have merged the better-match branch into main. Could you rebase off that and maybe squash this down into one commit?

Thanks again; this is great work.

technomancy commented 1 year ago

@andreyorst what you're saying about where vs and is really interesting. However, I'd like to keep this thread focused on the docs for the feature as it currently exists; can we start a separate thread about a potential change to case and flesh it out there first?

rktjmp commented 1 year ago

I've squashed the old commits but left new changes unsquashed just for review, if all ok I will squash them all down.

technomancy commented 1 year ago

Yes, please go ahead and squash this down, then I'll merge. Thanks!

technomancy commented 1 year ago

Thanks; I've merged this!