small victory: i managed to implement a love2d dialogue textbox system in fennel using only coroutines

this is the *entire* code to use this

render-text literally is just a coroutine closure that gets resumed every tick, and automatically handles how to render it based on the current time

this is what the closure actually looks like if you're curious! gist.github.com/Archenoth/d189

(i named it .clj because github doesn't recognize fennel)

basically, every tick, the coroutine to render a single line of dialogue resumes with a new time in scope, and based on that, renders a subset of text

after it renders a full line, it continues to a new yield loop to render the bouncy triangle at the bottom to note you can progress

and when the coroutine finally finishes, a new line takes its place

the magic is that resuming a coroutine just jumps right back to the place i yielded from, so i can break this coroutine into tiny pieces that get rendered every frame

meaning, i only ever need to interact with it in once place after making it; it's completely self-contained!

(i wonder how this compares to how scheme continuations work?)

oh, and if you are curious about the faces i drew in literally 5 seconds in mspaint because i needed something to test with, here they are!

anyway, fennel continues to be a super-cool language that i like lots, so it's cool finding excuses to use it more

@thingywott

coroutines function almost as a limmitted version of call/cc, gur limit is that they can only be resumed once for each yield

coroutines can actually be implemented with call/cc, something like

(def (m-coroutine yield-fn)
(show-dialog "* farts *")
(call/cc yield-fn)
(show-dialog "pardon me.")
(call/cc yield-fn))

(def co-resume (call/cc m-coroutine)
; * farts * is shown
(set! (call/cc co-resume))
; pardon me. is shown

@thingywott A lil bit of explaination, gur coroutine takes a function to call when its time to yield, gur yield function takes a funciton to call when its time to resume,

call/cc calls a function passing that function another function(ill call this gur "escape function") that can be called to return to gur point of call/cc 's execution (this function can be called an unlimitted number of times)
gur value passed to gur escape function is gur return value for call/cc

@bx oh, interesting!

i remember thinking i grokked how this worked a while ago, but never had an opportunity to try it in practice

it didn't even occur to me that continuations could be continued as many times as you liked from the same spot rather than just pausing a function and resuming

@thingywott yeah, not having to support that with coroutines really eases up gur implementation (and makes it easier to stay light weight)
i like to think of call/cc as functional setjmp/longjmp from C, since call/cc doesn't actually do any mutation!

My implementation was done in Pico-8's Lua (which is much much easier than doing it in C :P)
git.tilde.town/bx/lis.p8

@bx it's still a miracle to me that this exists, hahah

@thingywott Heheh, thanks :D

i find it kinda funny, cause after finish it i found out Factor also has call/cc and it just implements it completely differently (saving all gur stacks + current position then calling another func), where as I ended up writing in CPS style after reading about CHICKEN's internals

@thingywott gur reason we call gur co-routine with call/cc is so that we can come back to where we are when it yields, `yield-fn` is gur escape function supplied by using call/cc,
gur reason for yielding with call/cc is so gur co-routine returns it's own resume funciton

that might not be gur best explaination but i hope it helps!
(i had to implement call/cc myself to actually understand it)

@bx it does, thank you~ ^^

i've known about the existence of generators, coroutines, and continuations for a pretty long time, but i just never used them, so i didn't really internalize the differences between the three

so, when i finally had a reason to actually try out coroutines in fennel, it really seemed like something i could apply a lot more generally--but it also seemed similar to what i remembered thinking when looking at call/cc, hence my curiosity

@thingywott coroutines are absolutely lovely to work with for things like this, dialog, enemy ai, even handling gur response of diff ui elements when making tools,
gur web frame work itchio uses (I think its called Lapis?) lets you handle http requests with coroutines.
It's amazing how many things it feels like they can be applied to!

@bx i can see that now!

admittedly, i mostly stole the idea from @technomancy after seeing it used for scenario code here technomancy.us/188 (you can see the yield loops in both things)

it just seemed significantly nicer than making a more explicit super-linear state machine for something i'd want to isolate, and i just legit didn't even know this was an option

the end result wasn't particularly functional, but it was still a fun exercise i might actually use~

@thingywott @bx isn't it funny how you can read about it and kinda get a vague understanding of what it does, but it's not until you try it out that you realize how simple and applicable it is?

anyway looking forward to seeing what kind of stuff you make with this!

@technomancy underrated phenomenon tbh

because i think trying things out is infinitely cooler too

(also thank you..!)

@thingywott (btw I think github added support for Fennel recently so the .clj trick shouldn't be necessary any more)

@technomancy oh really??

it didn't instantly highlight in the gist editor when i gave it a fnl filename, but i'll have to try that next time!

Sign in to participate in the conversation
Awoo Space

Awoo.space is a Mastodon instance where members can rely on a team of moderators to help resolve conflict, and limits federation with other instances using a specific access list to minimize abuse.

While mature content is allowed here, we strongly believe in being able to choose to engage with content on your own terms, so please make sure to put mature and potentially sensitive content behind the CW feature with enough description that people know what it's about.

Before signing up, please read our community guidelines. While it's a very broad swath of topics it covers, please do your best! We believe that as long as you're putting forth genuine effort to limit harm you might cause – even if you haven't read the document – you'll be okay!