Hacker News new | past | comments | ask | show | jobs | submit login
The Min Programming Language (min-lang.org)
73 points by HaoZeke 73 days ago | hide | past | web | favorite | 21 comments

Worth noting this is called MIN because it is implemented (and embeddable in) NIM. Oh and a better description than a LISP in RPN is that it is a functional concatenative language.

Just in the last few days I've been playing around with my HP48 and wondering how close to a reverse scheme with no brackets RPL is.

I figured the only real difference is that scheme has list of lists, but you can't have a stack of stacks with RPL.

Really cool.

It has the first class function objects, but not the lexical scoping.

Try entering this and storing it into a variable:

    << -> x << << x >> >> >>
If you run that object with something on the stack, you'll get this in return.

    1:  << x >>
That x is a local variable reference, which makes it different than if you just entered this

    << x >>
And if you evaluate it, it blows up with an error to that effect. (Since RPL doesn't really close over the lexical environment.)

Years ago, I wrote a Scheme-based derivative of RPL that fixed some of this and found it rather fun to play around with.


Min has lexical scoping too.

I have a question, if you don't mind:

I have a stopwatch function in my HP48 that I don't want using a local variable (avoid polluting my precious menu), or having to keep it in a stack.

Instead I want the value of the last time I ran the program to be stored within the program itself. I believe this is called a closure in CS.

Right now I can have << value -> X 'expression' EVAL rest of the program >>

And it'll work just fine, but how could I get the value at the very top modified?

(I know my cell phone has a stopwatch. We're not allowed phones at work)

> I have a question, if you don't mind:

Not at all.

> I have a stopwatch function in my HP48 that I don't want using a local variable (avoid polluting my precious menu), or having to keep it in a stack.

The first thing that comes to mind is that there's a hidden directory at the root that the ROM itself uses to store stuff like this. This link talks a bit about how to get there:


This uses SYSEVAL to call into a normally-not-visible object that puts the name of the directory on the stack. From there, you should be able to read/write the variable.

You may also be able to do some hacky stuff with self-modifying code, but that's honestly something I'd avoid unless you want to try it for fun.

You can trivially change Scheme to RPL by simply putting the function name last, instead of first. Apart from that is would be the same. There doesn't have to be a stack either.

If you mean concatenative languages (like Nim), then the difference is that a function in concatenative languages can push and pull an arbitrary number of arguments. This makes it trivial for a function to return two arguments, of which the next to functions use one each. It makes it non-trivial to have var-args. Magic like having a function consume as many further elements as the number on the top of the stack says is of course also possible.

Edit: Oh sorry, I confused "RPL" with "RPN". I don't know about RPL.

That's actually another difference, although I think its small:

Scheme allows multiple arguments, RPL cannot. I.e.

(+ 1 2 3 ) evals to 6,

1 2 3 + evals to 1 5

RPL cant add your entire stack because presumably you have stuff in your stack you want to keep and not add.

But, if we put that aside, if RPL allowed:

[ 1, 4, 5, 6, [4 ,2 1, 6]]

where [] represent stacks, i.e. a stack can be an object in the stack, then the RPL would be very close to lisp.

Which is very close to what this min does.

RPL is one of the more interesting later developments from HP's calculator group. After the HP41C series, they realized that continue the development they wanted to do, they needed a higher level programming environment. To that point, my understanding was that it was all essentially machine/assembler level code written for their (fully custom) CPU architecture.

Their response to this was RPL, which borrowed rather heavily from both FORTH and Lisp. In keeping with their RPN user model and the light memory footprint of FORTH, RPL used a threaded execution model composed of a hierarchy of function (procedure?) object definitions. As with FORTH, these could be either defined in machine code or defined in terms of other RPL words. From Lisp, RPL borrowed the notion of tagged data objects and first class function objects. A user program written in RPL was composed of one or more function objects bound to variables. Keeping with FORTH, user program objects were in many ways peers of the objects built into the system ROM. Same format, execution, etc.

If you look at the documentation around these calculators, you'll see references to both "System RPL" and "User RPL". The real difference here is that when HP defined the words that were built into the calculator ROMs, only a fraction were given names within the ROM. These were the words that HP vetted for customer user and deemed safe (by ensuring they all checked types, etc.) "System RPL" words didn't necessarily have the same type checking and couldn't be used without risk of corrupting memory etc. Of course, they were also faster and had some additional capabilities if used with care. These are how HP built the ROMs internally, and with HP's help, the internet community developed tools for non-HP folks to write so called "System RPL" and even machine code level software.

If you came at one of these RPL calculators from the perspective of one of the earlier traditional RPN calculators, this could all be unsettling. There were a number of various changes to the UI, starting with the fact that the stack was no longer bound at four levels. It's a definite change in perspective.

From the perspective of a new user, the calculators had a great deal of internal consistency to their software model that could make them a lot of fun to use. It was in many ways 'turtles all the way down', which meant that even if you never used the system functions, you still could pretty easily write hook functions for the the REPL, custom menus and key bindings, and all with what would in these days be described as first class functions bound to event handlers. (On a 4-bit custom CPU that would run for weeks on three AAA batteries.)

One final aspect I'll leave you with is that, while the flagship calculators were almost all still RPN, HP also used this platform internally for a number of other non-RPL models. Some of the business calculators, the HP38, etc. all used this software, even though they did not necessarily expose a stack through their UI.

I miss RPN on my calculator. It makes so much sense.

An added plus would be we wouldn't have to deal with "viral equation" PEDMAS nonsense like 8 รท 2(2+2).

You can still get RPN calculators. Here's a thread with some discussion: https://news.ycombinator.com/item?id=10571218

"I miss RPN on my calculator."

I'm about to bite the bullet and buy a 48GX to replace my G which has annoying buttons (My original G+ died when I got caught walking home in the rain).

$200 for a used 20 year old calculator.

" It makes so much sense."


> my G which has annoying buttons

One thing I've always liked about those calculators is the fact they actually injection molded the keys with two colors of plastic... one for the body of the key and another for the marking. There's essentially no way to wear off the label, since it is intrinsically built into the key itself. They stopped doing that with the 49 and follow-ons, and I don't think the new HP11 does it either. Arguably, the original was overengineering, but there's a reason these things are still worth as much as they are today.

If you watch MIT's CS 101 class on their OpenCourseWare (the one filmed in the 80s) you'll see Sussman and Abelson teaching scheme to a class full of electrical engineers from HP.

I think these are guys are the guys who designed RPL

Somewhat relevant: SHUNTING-YARD

This is a concatenative language, not a Lisp. In Min a function can push and pull an arbitrary number of arguments from the stack. This also makes varargs non-trivial. The round brackets are for creating quotations, and not for executing functions like in Lisp. Maybe the Web-site should make that clearer.

Apparently it doesn't have macros either, it can only manipulate functions.

Edit: Maybe the mods should change the title. @dang

We've changed to the page's title. Submitted title was 'Lisp in RPN'.

This looks pretty cool. Nice website, but I'd like to see more examples.

Can I access Nim functions in Min?

>Fully homoiconic, all code can be accessed as data via quotations.

( https://min-lang.org/ )

>quotation >A list of elements, which may also contain symbols. Quotations can be be used to create heterogenous lists of elements of any data type, and also to create a block of code that will be evaluated later on (quoted program). Example: (1 2 3 + *)

( https://min-lang.org/learn-data-types/ )

Apparently Min functions are lists of the symbols they consist of, and can therefore be manipulated.

No I mean can I use certain aspects of Nim (Ex: some function in the stdlib) in this?

Oh, I didn't read closely enough.

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