~technomancy/fennel

fennel: Re: Clojure-like loop/recur or Scheme named-let in Fennel? v1 PROPOSED

On Sat, May 27, 2023 at 1:38 AM Andrey <andreyorst@gmail.com> wrote:
> >Oh yeah! (I was the one who wrote it! Ahah)
>
> Oh, haha, you're right!
>
> >I remember seeing these limitations the last time I referenced the
> >library to talk about this in #fennel~
> >
> >I wonder if there's a better way to implement it? (Or maybe even a
> >better place?)
> >(Actually, where would I even need to look if there was?)
>
> Well, IIRC I was sitting and thinking of a different way, and the only
one that
> comes to mind is literally using GOTO labels. This will turn named let
into a
> simple jump + rebind, and it will probably be possible to support
> multiple-value binding. Probably. (Un)fortunately, lua escape hatch
doesn't
> allow defining goto labels.

I figured out a way to bypass these limitations in a way that doesn't
involve introducing GOTO, doesn't break with the caveats that the cljlib
implementation has (afaict), and changes no existing syntax at all (and
validates in the same way as existing let!)

Archenoth (1):
  add named let!

 src/fennel/specials.fnl | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

-- 
2.38.4
#997582 .build.yml failed
fennel/patches/.build.yml: FAILED in 55s

[Re: Clojure-like loop/recur or Scheme named-let in Fennel?][0] from [~archenoth][1]

[0]: https://lists.sr.ht/~technomancy/fennel/patches/41463
[1]: mailto:archenoth@gmail.com

✗ #997582 FAILED fennel/patches/.build.yml https://builds.sr.ht/~technomancy/job/997582
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~technomancy/fennel/patches/41463/mbox | git am -3
Learn more about email & git

[PATCH fennel 1/1] add named let! Export this patch

From: Archenoth <archenoth@gmail.com>

This commit will allow for `let` bindings to optionally specify a name
in the same way that `fn` can in order to restart its body with new
bindings (Like how Scheme does it!)
---
 src/fennel/specials.fnl | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/src/fennel/specials.fnl b/src/fennel/specials.fnl
index 503ddd9..339dbb5 100644
--- a/src/fennel/specials.fnl
+++ b/src/fennel/specials.fnl
@@ -451,8 +451,18 @@ and lacking args will be nil, use lambda for arity-checked functions." true)

(fn kv? [t] (. (icollect [k (pairs t)] (if (not= :number (type k)) k)) 1))

(fn compile-named-let-fn [ast scope parent opts name bindings]
  (let [args (icollect [i v (ipairs bindings)]
               (when (= 1 (% i 2)) v))
        body (icollect [i l (ipairs ast)]
               (when (> i 2) l))
        declaration [:fn name args (table.unpack body)]]
    (SPECIALS.fn (utils.list (table.unpack declaration)) scope parent)))

(fn SPECIALS.let [ast scope parent opts]
  (let [bindings (. ast 2)
  (let [name (when (and (utils.sym? (. ast 2)) (utils.table? (. ast 3)))
               (table.remove ast 2))
        bindings (. ast 2)
        pre-syms []]
    (compiler.assert (and (utils.table? bindings) (not (kv? bindings)))
                     "expected binding sequence" bindings)
@@ -469,11 +479,13 @@ and lacking args will be nil, use lambda for arity-checked functions." true)
        (compiler.destructure (. bindings i) (. bindings (+ i 1)) ast sub-scope
                              sub-chunk
                              {:declaration true :nomulti true :symtype :let}))
      (when name
        (table.insert ast 3 (compile-named-let-fn ast scope parent opts name bindings)))
      (SPECIALS.do ast scope parent opts 3 sub-chunk sub-scope pre-syms))))

(doc-special :let ["[name1 val1 ... nameN valN]" "..."]
             "Introduces a new scope in which a given set of local bindings are used."
             true)
(doc-special :let [:name? "[name1 val1 ... nameN valN]" "..."]
             "Introduces a new scope in which a given set of local bindings are used.
Optionally allowing for a name to restart the body with new bindings" true)

(fn get-prev-line [parent]
  (if (= :table (type parent))
-- 
2.38.4
fennel/patches/.build.yml: FAILED in 55s

[Re: Clojure-like loop/recur or Scheme named-let in Fennel?][0] from [~archenoth][1]

[0]: https://lists.sr.ht/~technomancy/fennel/patches/41463
[1]: mailto:archenoth@gmail.com

✗ #997582 FAILED fennel/patches/.build.yml https://builds.sr.ht/~technomancy/job/997582