Programming thread

  • 🐕 I am attempting to get the site runnning as fast as possible. If you are experiencing slow page load times, please report it.
Distinguishing between operators and functions at all is niggerlicious.
I've been implementing my own lisp recently having never used a lisp before, and I have been pleasantly surprised at the elegance of prefix notation, specifically how you can have an "operator" be N-nary rather than be limited to two operands with infix notation, so what would be an "add" operator in an infix expression, allowing only 2 operands and requiring parsing of precedence, in the world of prefix notation basically doubles as a sum function because you can have any arbitrary amount of operands, also you don't need to care about precedence because your program is already a syntax tree when you write it which is nice too.

I hate common lisp's boomer naming, so rather than do that, I went off my limited knowledge of lisp, which is basically just s-expressions and prefix notation and I figured out what features I wanted from there and named them how I wanted. deal with it. inb4 "cat" is boomer naming. Yes, but I like it so it gets a pass.

Code:
(def name "nigger rapist")
(print
  // `cat` is string concatenation
  (cat "hey " name ", you are a stupid nigger!\n"))

(def FACT_PATH "factorial.nig")
(println
  (cat "Anyways, gonna load some external code from `" FACT_PATH
    "`, then calculate the Nth factorial defined in the file."))

// works like source(1) in shell
(src FACT_PATH)

(print
  (cat "computing " N_TO_COMPUTE "th factorial:\n"))

(println
  (factorial N_TO_COMPUTE))

(println "Am I huwhite now, kiwibros?")

Code:
// factorial.nig
(def N_TO_COMPUTE 1000)

(def factorial
  (fn (n)
    (if (< n 2)
      1
      (* n (factorial (- n 1))))))

And running it with my NiggerLisp interpreter
1732077140207.png
Lisp truly is the white man's language

Lambdas are of course real nigga lambdas
Code:
(src "factorial.nig")

(def factorials
  (fn (from to pred)
    (if (< from to)
      // do runs all the expressions contained within, but only returns the last expression's result
      (do
        (pred from (factorial from))
        (factorials (+ from 1) to pred)))))

(def padprint
  (fn (n f)
   (if (< n 10)
     (println (cat " " n ": " f))
     (println (cat     n ": " f)))))

(factorials 5 15 padprint)
1732079034720.png

This makes me want to go and fully learn a functional language. Any suggestions? From what I have read, people seem to like scheme and ocaml a lot.
 
I've been implementing my own lisp recently having never used a lisp before
I would seriously recommend learning Common Lisp if you've never used Lisp before. Prefix notation and homoiconicity are nice, but you're still missing out on a lot if you just add parentheses to a language of your choice.
 
This makes me want to go and fully learn a functional language. Any suggestions? From what I have read, people seem to like scheme and ocaml a lot.
I second @306h4Ge5eJUJ's suggestion and back it up with this: Common Lisp has more libraries than Scheme and that CL implementations are made to be compatible with each other, while Scheme implementations are often incompatible. There is a reason why Scheme has the moniker of "most unportable language".
Edit: I do not have experience with OCaml so I cannot say anything on the matter but @Marvin surely does know better than me.
 
I second @306h4Ge5eJUJ's suggestion and back it up with this: Common Lisp has more libraries than Scheme and that CL implementations are made to be compatible with each other, while Scheme implementations are often incompatible. There is a reason why Scheme has the moniker of "most unportable language".
I've always been a big fan of Scheme, but I've always had immense respect for Common Lisp, even if just because of the influence it's had on things, but also especially after having messed with a handful of CLOS-inspired Scheme OOP systems.

I've used Chicken's COOPS as well as Guile's GOOPS. They're the most elegant approach to OOP I've ever seen. Sorry C++ and Java/C# (or may allah forgive me for uttering this, Javascript's prototype OOP nonsense), but CLOS-style is far, far superior.

But to be fair, I haven't really experimented much with the message passing style you see in Ruby or Smalltalk, so, there's still space for me to explore.

The Scheme standards are indeed very small and leave a lot up for interpretation for the implementation to fill in, so you end up with a bunch of incompatibilities.

I think that's a good thing depending on your use case. If I was going to implement a game engine, I'd embed a small Scheme interpreter, largely because it sorta doesn't matter because the language is going to be hyperspecific to the use case of my engine.

If I was going to write a large web app, a respectable Common Lisp implementation is probably nicer to work with.

lol you could always go with Paul Graham's Arc if you wanted to...
Edit: I do not have experience with OCaml so I cannot say anything on the matter but @Marvin surely does know better than me.
OCaml is basically the one ML family language that took off, mostly because a random fintech company in NYC adopted it.

SML is solid too, but mostly only relevant for historical reasons. Although there is MLton, which is an absurdly efficient compiler for SML.

The ML family is neat to explore if you've worked with weaker typed languages like Java or C++.

It might be kind of a bumpy ride at first, because the type system will be much more constraining than you're used to. But gradually as you do get used to it, you'll learn to encode expectations into the type system itself.

It's also a treat to refactor code in such a strictly typed language like ML, because you just break the code in one place (say add a new variant tag), and then the code breaks all over, and as you gradually fix the places the compiler complains, you end up with a working program. You almost don't even have to test it. (You still should, obviously, but you'll start to develop much more confidence in the code you're putting out.)

Haskell has similar intellectual origins to the ML langauges, except it's 100% strictly functional. Which is a little extreme for my tastes and use cases.


In other news, job hunting fucking sucks. I'm job hunting and one role I'm considering is a Python shop. I really don't like everyday work in Python, not because it's necessarily a bad language, but there's a lot of bad code out there written in Python.

But still, I gotta pay the bills.

So I'm going to be taking a break from my hobby project in Ocaml to work on a little Python project to refresh my memory to pass the interview stages.
 
Last edited:
Mini rant:
I FUCKING LOVE RAII. If there is one thing C++ has done right it will be RAII
Using try-with-resources in Java or defer in Go is such a gimped way of doing what simple ctor/dtor combo can do for you.
I like C a lot. I do not like OOP a lot. RAII is perhaps the best part of C++ in terms of how it cleans code up. Hard agree.
 
Now imagine RAII but move semantics are always explicit
Yeah, I know Rust is awesome. I would probably enjoy it, but:
Nowadays I program in C++ only for personal projects, and I trust myself for them to be generally good enough. I also like to abuse templates, constexpr and concepts.
I need static reflections though ;/

Also if I wanted a serious correct program I would use Haskell. Cause I like to pretend to be ivory tower genius. :smug:

you don't have to delete 3 default constructors just to ensure you don't copy a struct by referring to it in the wrong way.
Snippet engine goes brrrrrrrr
 
What's wrong with defer?
Nothing really, in GC language where finalizes are not guaranteed to be called it's decent solution, definitely better than try-with-resources.
It's just that having destructors called on lifetime end is just more convenient once lifetime goes beyond single function scope. As you will have to remember to call cleanup function manually in every possible code path.

You could trivially create defer with RAII + Lambdas(or anything callable really) in C++. RAII is just more powerful tool. And it really feels like logical extension to structured programming.

Also RAII is unfortunate acronym. Scope-Bound Resource Management is better, Rust's Ownership Based Resource Management is even better in explaining what it is about.
As biggest benefit is not initialization, but release of resources.
 
real nigga lambdas
Code:
(((((λ (y)
      ((λ (f) (y (λ (x) ((f f) x))))
       (λ (f) (y (λ (x) ((f f) x))))))

    (λ (factorials)
      (λ (from)
        (λ (to)
          (λ (res)
            (if (< from to)
                (((factorials (+ from 1)) to) (cons ((((λ (y)
                                                         ((λ (f) (y (λ (x) ((f f) x))))
                                                          (λ (f) (y (λ (x) ((f f) x))))))

                                                       (λ (fac)
                                                         (λ (n)
                                                           (λ (res)
                                                             (if (< n 2)
                                                                 res
                                                                 ((fac (- n 1)) (* res n)))))))
                                                      from) 1)
                                                    res))
                res))))))
   5) 15) '())
Output: '(87178291200 6227020800 479001600 39916800 3628800 362880 40320 5040 720 120).

Written in Scheme because Scheme is based. NiggerLisp looks really cool though.
 
Is there any JSON library for C/C++ that's considered "standard"? There are a million of them but I don't have any particular intuition on which one is best.
 
  • Thunk-Provoking
Reactions: UERISIMILITUDO
After reading a Medium article recommending Neovim and reflecting on the discussion I had either here or in the Linux thread, I finally took the plunge and installed the latest stable version and have succeeded despite the initial difficulty in dicking around a bit and getting it to do things I wanted. The documentation, as I've seen others have commented, is not at all as good as it for Vim. I don't know how it possibly could be given how long Vim has been around but it could definitely be better. It took a while for me to translate GitHub instructions on how to configure plugins to how to do it in LazyVim, though that is now straightforward (so far). Also I had to figure this out (no Lua highlighting on the forum):
Code:
vim.opt.whichwrap:append({
  ["<"] = true,
  [">"] = true,
})
But speaking of LazyVim, it's made so much of what's in my .vimrc unnecessary. If you want to learn how to use Neovim, whether a previous Vim user or not, start here with a book about Neovim, using LazyVim right from the rip. All sorts of things like rainbow parentheses and using actual tabs in Makefiles did not require any extra configuration. Still, I'm gradually bringing Neovim closer into line with how I had things earlier:
Screenshot 2024-11-25 07:58:00.png
(I'm using the cyberdream.nvim colorscheme BTW.)
 
For getting started with nvim I like this video, he's a maintainer for nvim. I've gone back and forth between nvim and vscode for personal reasons, currently using vscode again. The only thing holding me back from nvim is having to setup a visual debugger and learn to use it, cba, but once you get your own personal config setup it's comfy to use and faster than any other editor.

 
  • Feels
Reactions: Belisarius Cawl
Back