Salta al contenuto principale


#BabelOfCode 2024
Week 8
Language: Fennel

Confidence level: High

PREV WEEK: mastodon.social/@mcc/114433465…
NEXT WEEK: mastodon.social/@mcc/114463342…
RULES: mastodon.social/@mcc/113676228…

Lua is my favorite programming language. Because of Reasons¹ I have stopped using it, but it is still a jewel of design to me. Any description of what I want in a programming language will sound like "Lua, but—"

Fennel is "Lua, but with LISP syntax". Which is… if anything the opposite of what I want. Hm.

¹ I NEED TYPES


#BabelOfCode 2024
Week 7
Language: Haskell

Confidence level: Medium low

PREV WEEK: mastodon.social/@mcc/114308850…
NEXT WEEK: mastodon.social/@mcc/114463342…
RULES: mastodon.social/@mcc/113676228…

I was going to do Fennel this week, but then I looked at the problem and thought "this is ideal for Haskell "amb". I have been looking for an excuse to use Haskell "amb" for 25 years. So Haskell.

I have tried to learn Haskell 3 times now and failed. This "Babel of Code" thing was originally in part an excuse to do Haskell


Questa voce è stata modificata (5 mesi fa)

Oblomov reshared this.

in reply to mcc

I have twice now (once for this project's "week six") made languages I could argue are Fennel's opposite ("LISP, but with Lua syntax"). So I'm not sure this language is for me. As soon as I started reading the tutorial I felt I'd maybe made a mistake. Still, I'm trying it, just to see what it's like, and to see how well basing a language atop Lua turns out. (And because I want to eventually understand @SpindleyQ 's "HoneyLISP" git.information-superhighway.n… .)
in reply to mcc

The first thing I notice looking at Fennel is that the documentation feels a bit skeletal. I couldn't figure out how to take command line arguments and the "cookbook" lists "file I/O" under "TODO". It turns out I was supposed to just look up the Lua documentation for that stuff, but Fennel syntax for (for example)calling methods differs between Lua and Fennel. So this was pretty confusing without a Fennel-flavored version of the docs.

The docs mention a "fennel.view" that doesn't seem to exist.

in reply to mcc

Things I notice right off the bat:L

1. There's no "break" statement. There's a "break" statement in Lua, which Fennel compiles to directly, so compiling Fennel just basically… erases itself but censors code with a break in it. This is on purpose. lists.sr.ht/~technomancy/fenne…

Adds parentheses; removes "break"; I don't think this language is for me.

2. The syntax highlighting is pretty much exactly what I wanted for my nameless experimental LISP so I should cannibalize their sublime-syntax file lol

in reply to mcc

Currently blocked on:

I have the line

(if (and line (> (length line) 0)) (

I *assume* that `and` is a short circuiting form, and I *assume* that this code will test whether line is a non-nil string with length greater than zero. Instead, it fails with

runtime error: attempt to call a nil value

On this line. If I try to break out the values onto different lines, it appears this is specifically being called on whatever line contains "0"

0 is a function? :/

in reply to mcc

(I view my issue in the previous post as downstream from "the documentation is subtantially vibes". Okay so it's basically Lua and you do things however you do them in Lua. Oh except it's not # it's called "length". And it's not called ~= it's called "not=". And . is now prefix instead of infix but NOT :, : is infix just like in Lua. All of this is fine, except they didn't just, *tell* me any of it, I had to reverse engineer it from comments in the middle of the very long "reference" document.)
in reply to mcc

Okay so it appears Fennel's ability to identify on what line an error occurred is spotty. The problem was on a different line. Here is the actual problem: For the "true" clause of my if statement, I put

( (print line) (print "\n") )

That's not two statements; it's a function call, where it takes the return value of "print" and calls it with the value of "print \n" as an argument. If I'd wanted an if with multiple statements, I should have said "when". But then there's no "else" feature. Yikes?

in reply to mcc

(Post edited)
Similarly, there's an awkward asymmetry where "local" creates a entire-scope immutable variable, and "var" creates an entire-scope mutable variable, and "let" *creates* a scope with a local variable within it, but there's no "let" equivalent for var… which tripped me up and interacts pretty poorly with the "while" construct lacking a "break" since you need to create a variable… these are all papercuts, but with each line of code I write I feel like I'm stepping on a different rake.
Questa voce è stata modificata (5 mesi fa)
in reply to mcc

Okay I'm being mean about design minutae, so I'll say one thing I like about Fennel: It has a construct that lets you mark a line as a "proper tail call" (eligible for TCO) explicitly, such that you get an error if that turns out not to be true. That is a feature I would like in normal Lua. (Normal Lua has TCO but if you typo it somehow there's no notification until your stack overflows.)
in reply to mcc

Continuing with "Lua ergonomic niceties Fennel has removed", it appears Fennel has removed Lua's [[string with internal quotation marks allowed]] syntax and replaced it with… nothing. fennel-lang.org/reference#:~:t…

I'm harping on this, but remember: *The point of Fennel is to be Lua with a better programmer interface!* If you're going to sell yourself on "we fixed Lua's rough edges" then you really should have *fewer rough edges*. Otherwise why not keep the Lua syntax and add a macro preprocessor…?

in reply to mcc

Fennel question:

I want to include a library "vec2.lua". It is in the folder "cpml/modules". I run fennel with --add-package-path and say "require :vec2". It says it cannot load the file "vec2.lua" because it is inside of "modules", which is a directory. Well, yes. Isn't that the normal place to store files? I don't know if this is a Fennel problem or a Lua 5.4 problem. I've never used command line Lua, only embedded.

in reply to mcc

I next tried instead of adding the directory with --add-package-path, adding each individual file in that directory with its own unique --add-package-path. This is going… badly.

Maybe I should use LuaRocks. The Fennel documentation implies LuaRocks is supported.

in reply to mcc

Ah okay so this is actually telling. it's a Lua problem not a Fennel problem! But it's a Lua problem which is badly exacerbated because Fennel's documentation is less explicit than it could be. The problem is that --add-package-path becomes an explicit member of LUA_PATH, which means it needs LUA_PATH's baffling "?" format.

fennel --add-package-path "cpml/modules/?.lua" src/test-cpml.fnl

…works. I figured this out not from Fennel docs but from reading old Lua library issues and intuition.

in reply to mcc

Okay heck yeah!

So I now get to leverage one of Fennel's best features: Lua library compatibility! I can import CPML¹, which is a Lua vector-math library I love.

Now, the process of adding the library was miserable, but adding libraries is *also* miserable in *vanilla* Lua, so this is not a point against Fennel.

(Also, I had to slightly mod how the library imports its internal deps, but I don't think that's Fennel either, I think it's a Lua5.4/5.1 problem)

¹ "Cirno's Perfect Math Library". ⑨

Oblomov reshared this.

in reply to mcc

it sucks that torch7 isn't maintained anymore
in reply to bob

oh this is a math library like glm not a math library like lapack
in reply to bob

@bob yes, like glm. But there is a branch point in the last 7 years where I was like "ok could I use ML to solve this problem? I'll use Torch. Oh it's been turned into PyTorch now . Ehhh I guess I don't need to solve the problem bad enough to learn a new tool" and I simply didn't learn torch
@bob
in reply to mcc

So in my "unnamed LISP" from week 6, one of my more dubious decisions was that in the "sugar syntax" mode, a ( ) is not allowed to span multiple lines. If you want it to, you have to use an explicit \

Writing a more "normal" LISP and getting a ") expected" error at the end of the file: Wow! I was actually right!

in reply to mcc

Yeah, okay. That's part one.

github.com/mcclure/aoc2024/blo…

Once I figured out what Fennel wanted of me, and figured out what Lua 5.4 "require" wanted of me, that was very rapid and easy. It felt like more friction than normal Lua and I don't know if the code I produced is very readable to a regular Fennel user but, well, it was just funny-shaped Lua, and I like Lua.

In this program I used one (1) feature which is present in Fennel but not Lua ("value if"/ternary, in exactly one place).

in reply to mcc

Uh… yeah. Hm. Okay.

Part two required a change of four lines removed, five lines added, and I completed it in four minutes and forty seconds. (Yes, I was running a stopwatch.)

github.com/mcclure/aoc2024/blo…

Either "day 8" just happens to be a easy puzzle, or the AOC Author thought this would be harder because they assumed you don't have access to a vector math library and you'll trip over manipulating 2D coordinates. Luckily I have the assistance of the strongest warrior in Gensokyo

Oblomov reshared this.

in reply to mcc

This was the only AOC "day" so far I actually completed on the same day I started it, which I'm chalking up to it being so close to a language I'm already skilled with.

I *was* hard on Fennel in this thread, but my issues *do* mostly come down to "this is a language for LISP fans and I am not a LISP fan". (Or running headlong into underlying problems with Lua — LUA_PATH confusion— that Fennel merely inherits.) I guess if you like LISP, try Fennel and see why Lua users like Lua.

Project status:

Oblomov reshared this.

in reply to mcc

this is a bit unfair though. Maybe you should call it a mulligan and restart with a language unfit for the problem and that you are less familiar with 😉
in reply to mcc

I was having my morning coffee when I stumbled upon your thread, and it was an interesting read. Thank you.
in reply to mcc

i keep wanting to read this like Fennel is the name of a person, fits stereotypical enby naming conventions too well
in reply to mym

@mym Yes I know a Fennel and they're very sweet
@mym
in reply to mcc

vars are scoped. you can write a macro
(macro with [vars & body]<br>  (assert (= 0 (% (length vars) 2)) "expected even number of name/value bindings")<br>  (let [out body]<br>    (for [i (length vars) 1 -2]<br>      (table.insert out 1 `(var ,(. vars (- i 1)) ,(. vars i))))<br>    `(do ,(unpack body))))<br><br>(with [x 1 y 2]<br>  (set x 2)<br>  (print (+ x y)))<br>(print x) ; nil<br>
Questa voce è stata modificata (5 mesi fa)
in reply to mcc

any builtin that takes forms like do and let and for* and while and each
in reply to mcc

`var` persists exactly as long as `local`, which is "the current lexical scope" (ie. the rest of the function, let-block, do-block, etc). `let` just combines creating a new lexical scope with binding new values to names, it's not particularly special.
in reply to mcc

I hope I am being helpful and not obnoxious! Definitely agree that the docs are not ideal, especially for a language with Opinions that aren't necessarily self-evident. (I also don't necessarily agree with all of Fennel's Opinions! I think mostly I just like Lua and dislike commas, haha)
in reply to Phill

@phillbee What?

The reverse engineering? Frankly no because the language is (by design) simply not very long. I believe after one evening with the language I'd found all such points probably.

in reply to mcc

it seems people are changing the programming language purposely to gatekeep.
in reply to mcc

what's the full expression? The snippet looks fine. The line numbers in tracebacks are... often not quite right. This sucks a lot.
Questa voce è stata modificata (5 mesi fa)
in reply to Spindley Q Frog

The error is on line 10. This loop runs once successfully, and on the second iteration line 10 fails. If it's not clear it's reading in a file line by line and printing each line.
Questa voce è stata modificata (5 mesi fa)
in reply to mcc

@SpindleyQ Actually I think the problem is that in my if I'm doing

(
(line1)
(line2)
)

Whereas in fact "if" only supports a single line. Is there like a "sequence" that lets you call multiple lines in-place?

in reply to mcc

you can either do
(when cond
expr1
expr2)
Or
(if cond1
(do expr1
expr2)
cond2 expr2
else-expr)
in reply to mcc

gist.github.com/plt-amy/9d25be… i thought it would be fun to write a macro for break too
in reply to mcc

yeah, fennel intentionally does not require a runtime separate from lua's, but you can write
(local fennel (require :fennel))
to load the compiler and its helpers (including fennel.view) if your fennel code is running under conditions where that package exists. (I assume the commandline interpreter has that module preloaded, but I haven't actually used it much.)
in reply to Spindley Q Frog

Is there a better way to access fennel.view than that? I normally pull in a library to get that function when using Lua.

EDIT: Sorry I mean: is that the recommended way, or is there something that does fennel.view implicitly?

Questa voce è stata modificata (5 mesi fa)
in reply to mcc

Just want to let you know that I appreciate you writing all this. I'm not boosting or favouriting it because the whole thing seems a bit naff, but I do appreciate reading about these things. Thank you.