Hacker News new | past | comments | ask | show | jobs | submit | Twey's comments login

My favourite litmus test for ‘can LLMs reason about code?’ is to make up a programming language with familiar syntax but weird semantics. E.G.:

- all variables contain signed integers

- all variable names have block scope

- there is no variable declaration syntax: all variables are implicitly initialized at first use with the value 5

- all integer literals are expressions

- the expression `a + b` means to subtract the value on the left from the variable on the right, returning the previous value of the variable

- a program is a block

- a block is a sequence of statements enclosed in braces and separated by semicolons, and executed from bottom to top

- conditionals are introduced by the keyword `while`, followed by an expression, followed by a block that is executed only if the expression evaluates to 4

- loops are done by simply prefixing a block with an expression; if the expression evaluates to 0, the block will run indefinitely, otherwise the block will run a number of times indicated by the negation of the value

Et cetera. Then I ask the LLM to write a simple program (e.g. FizzBuzz). Even with a lot of hand-holding, I've yet to get an LLM to do this successfully, or even to answer questions about a program written in the language.


I actually had pretty good results from taking a new language that was posted here and having GPT-4 try to interpret it. I don't remember what it was called, but it was APL-like, very symbol-dense, but not using standard symbols. It was too new to be included in any training data at the time, but GPT-4 did a good job of figuring out what each symbol meant.

I think it's not impossible for LLMs to write code like you're wanting. Maybe it's actually harder to redefine common idioms, but to be fair that happens with people too:

https://en.m.wikipedia.org/wiki/Stroop_effect


My favorite test is to ask the LLM to approximate the mental processes going on in my brain, and based on that, divinate what food I had for dinner last thursday. /s

I’m honestly quite tired of reading people’s favorite ways to break the LLM, like it’s some kind of an achievement. Always in the context of “See? It doesn’t really reason/know/understand X!”.

Yes, it breaks when asked to do complicated stuff. GPT4 was worse at it than o1, GPT3 broke on trivial queries, and GPT2 couldn’t do anything done. I don’t even interact with LLMs often, and I find this whole topic to be breathlessly obvious, boring and unproductive, and yet every single conversation about LLMs devolves into it. Sorry about the rant, but it needed to come out at some point.


I interpret a ‘fence’ here to mean a hoop the programmer explicitly has to jump through — something like Rust's `unsafe`. It doesn't need to be difficult to do but it should be difficult to do by accident :)


> Agreed, OOP is orthogonally opposite of pure functional programming. Objects have state. Big revelation.

I don't think that's quite true. Having state or not isn't a dichotomy but a continuum about the size of the scope of the state. Objects (in either the Kay sense or the Java sense) exist to encapsulate state, to limit its scope and make it easier to reason about. That puts OOP (state is local to objects, and can be cleanly reset by destroying and recreating the object) somewhere between ‘pure imperative’ (only global state; there is no reliable way to reset the state) and ‘pure functional’ (state is limited to being kept in function arguments and return values, and is reset on each function call) on the continuum.


The irony of the comments in this thread decrying this as a classic example of too much abstraction is that the reason you rarely see three-star variables in C is that, while it's common to have long chains of pointers (and in languages where ~everything is a pointer~ most things are pointers by default, like Python, Java, or JavaScript, you definitely have pointer chains that are much longer than 4!), what is uncommon (but not nonexistent) is the need to manipulate more than two levels at once — you'll have one, maybe two, levels of pointers, but anything deeper is probably going to be hidden in a struct whose internals you don't have to care about (i.e. abstracted away). The same argument applies to channels, which are roughly to concurrent code what pointers are to sequential code: the fatal flaw here, if there is one, is not too much abstraction, but perhaps too little abstraction.

But then, I don't know the codebase — maybe a `chan chan` was exactly the right abstraction for what they were trying to write :) Certainly in highly-concurrent languages like Erlang, it is very standard practice to send a PID to another PID, for example to identify the process that should receive the reply to the message.


Heh! I remember getting shit about this early in my career because of a 3-star commit, because wtf is wrong with someone who needs a pointer to a pointer to a pointer?

But it wasn't; it was the address of an array of strings. Because C. It was the most straightforward solution, which I maintain to this day (some 20 years later).

(In my co-worker's defense, it probably had no comments. That part was on me.)


I think the biggest problem with these indirections isn't necessarily the amount of layers, but that they are unnamed (and naming isn't really well supported in most languages outside of just typedef-ing symbols).

***char vs *array<string> (or something similar)

Or in the article's case, naming what the 2/4 layers of channels were.


If you feel comfortable with Math A but not Math B you might enjoy _Graphical Linear Algebra_[1], which is specifically that bridge!

As someone who is decent at Math B but mostly incompetent at Math A I suspect it comes down to the old analysis vs algebra opposition — being better at thinking about things visually/spatially vs linguistically. Both are trainable though.

I think the approach outlined here works well enough. When teaching us about adjunctions, our category theory lecturer used to have us recite the definition of a left adjoint at the start of every lesson, and he'd draw the diagram as we spoke. I can't say I can still recite it by heart but I do feel like I have a decent intuition for adjoint functors.

[1]: https://graphicallinearalgebra.net/


As GP implies, NixOS supports running multiple instances of any service you like, but the way some of the modules are written doesn't make it easy. Thankfully one of the advantages of NixOS is that it's pretty easy to add a configuration module to your personal configuration!

In general, you can configure systemd yourself through `systemd.services`, where you can write systemd service files ‘directly’ in Nix syntax. Services for which multiple instances make sense often (unfortunately, not always) provide configuration that allows you to specify multiple instances (i.e. their top-level configuration object will be a list or attrset of instance configurations). I've written a little bit about patterns to do this here: https://twey.io/nix-patterns/inputs-and-outputs/

If you needed, say, multiple instances of Postgres, it's not too challenging to copy-paste the nixpkgs implementation, change it a bit to parameterize the config on (e.g.) a service name for namespacing, then import that module into your NixOS configuration to allow you to define multiple instances. For example, I did this here for the Rainloop email client: https://github.com/Twey/dotfiles/blob/main/nixos/modules/ser...


I probably should have said “the easiest way”. I did know that you could define systemd services yourself, but it’s good to see a specific pattern.

I still think it’s easier to just spin up a NixOS container - should work for any service out of the box.


You can take this idea further by trying to find computational analogues of more complex algebra structures and operations. For example, the derivative of a type function gives the type of ‘one-hole contexts’ of that type[0], which gives rise to the work on zippers for context-preserving transformation in functional data structures, things like Rust's `Entry` API for maps.

Amr Sabry has been doing work on extending this kind of ‘type algebra’ to negatives and fractions, with applications to reversible programming à la Kanren and quantum programming languages where breaking reversibility is an important effect, and I'm always kind of captivated by it when I see it. His original paper on it[1] is from 2012; he's produced a new paper[2] more recently that is more sophisticated but perhaps a bit harder to follow without a category-theory background.

[0]: https://pavpanchekha.com/blog/zippers/derivative.html [1]: https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&d... [2]: https://dl.acm.org/doi/abs/10.1145/3434290


Hey there, a bit late but I've read your other comments and I'd like to get in touch. I happen to be very focused on type derivatives, in the context of applying category theory to AI, having just discovered Conor's original papers. Your comment was extremely helpful. Please email me at [email protected] if you see this.


My `Accept-Language` looks like `en-GB,de-DE;q=0,8,…` and for some reason Notion:

    - interprets this as me preferring German
    - tries to retrieve a non-existent German version of the page
The HTTP semantics RFC[1] is quite clear that an unqualified value should be equivalent to 1.0, and I don't think content negotiation should ever prefer a non-existent resource to one that exists.

[1]: https://www.rfc-editor.org/rfc/rfc9110#field.accept-language


On that page I see entries such as:

  - Grease
  - HUMP
  - Lovetoys
  - Löve Bone
  - Gspöt
  - Möan
  - fLUIds
To be fair, I doubt most children will question the names! And this is a small enough subset of the libraries that one can just avoid them.


This isn't really a fundamental disagreement. If we think of array functions as functions `Array<Index1, Element1> → Array<Index2, Element2>`, then essentially all you need to be able to say is that a function is generic over `Index1` and calculates some output index type `Index2` as a function of `Index1`. This is perfectly possible to do with Rust traits or Haskell type classes (although not all that ergonomic).


Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: