HN user

gilch

79 karma
Posts7
Comments133
View on HN

C macros are just a text preprocessor. You could run the C preprocessor on a text file and have the result be Python code. Comments might be a little tricky, but it's doable. Or you can run a text file through a general-purpose one like m4.

For sum types we have enums, and for product types we have tuples (or namedtuples or dataclasses). Sugar could be done with decorators or metaclasses.

For Lisp macros, there's macropy and Hissp.

https://www.gnu.org/software/m4/

https://threeofwands.com/algebraic-data-types-in-python/

https://github.com/lihaoyi/macropy

https://github.com/gilch/hissp

Hissp 3 years ago

That is the right answer. While some comparisons have been written already, they're somewhat out of date. Hissp could use a new writeup. Let me know if I can answer any questions about Hissp, and when your blog post is ready :) You can reach me at the Hissp community chat channel on Gitter's Matrix: https://gitter.im/hissp-lang/community -- share your Hissp experience or get support.

Hissp 3 years ago

As the Hissp author/maintainer, I'd be interested in hearing about your take on Hissp's practicality (or lack thereof) in more detail.

Not accurate as worded. Python caches module imports in `sys.modules`, so all imports get the same one. A `reload()` will reuse the same dict object that was being used as the module's namespace, so everything with a reference to the module object will see the same namespace and get the updates.

What? Yes you can. I do it all the time.

    import code; code.interact(local=vars(foo))
where `foo` is the module object you want to set as current. This launches a subREPL in that module's namespace. (EOF kills the subREPL and returns to main.)

Python has a debugger in the standard library that can also do post-mortem inspections.

wanted to expand beyond python. [...] Have been trying to learn about Lisp lately and feel like I've come to a similar dead end.

If you're already comfortable with Python, check out Hissp's tutorials (in the docs). It's a Lisp hosted on Python, so you can focus on the Lisp concepts without getting so bogged down by learning a new standard library at the same time.

https://github.com/glich/hissp

I didn't really like "Learn You a Haskell". "Haskell Programming from First Principles" or "Haskell from the Very Beginning" might be more accessible.

And last but not least, what should I do about the fact that I have never used smartphones (iPhone/Android) and I have no interest in them, when the vast majority of my students will only have such a "computer"?

Android is basically Linux, which is great for development. You can install the Termux app (https://github.com/termux/termux-app) on Android phones, then you have a shell and a decent package manager. You can install compilers and interpreters and text editors. Python, Emacs, and so forth. (And shell is a scripting language in its own right.) The Play Store version of Termux is kind of crippled, so you'd want to sideload. It might be easiest to sideload the F-Droid store first and install from there. Recent versions of Android (12+) also aggressively kill processes to save battery life, which makes Termux much less usable. It takes some technical know-how to turn that off, but there are instructions linked in the Termux repo.

I'm less familiar with the iPhones, but they're a lot more locked down. I'd expect Android phones to be more common because they're cheaper, but sufficiently old iPhones are not that expensive either. There are some iOS IDE apps, but I don't think they're quite as complete as Termux can be.

Single-board computers like the Raspberry Pi are fairly cheap and can run Linux. I think even iPhone users can ssh into a server. Linux is multi-user, so students could share. Simple command-line apps don't require a very powerful computer by modern standards.

There are also a number of online IDEs that would only require a decent web browser. Some of them might be compatible with iPhone Safari. I'd consider JupyterLite, which is free and runs entirely in-browser. https://github.com/jupyterlite/jupyterlite

It occurred to me that ChatGPT (or the like) might be able to help students find their mistaken assumptions without taking as much of your time, at least if it's in a well-known language like Python. Being able to dialogue with these new AIs will probably become an important programmer skill anyway. However, if they use it as a crutch to avoid developing their own mental models, it could be net harmful. An outright ban is probably unwarranted, but they eventually need to be able to code without the assistance. If you have a small enough number of students, you could pair program (another important programmer skill) with each individually.

If I could send a message to my past self on the topic, I might have told myself to start with Common Lisp, Scheme, Python or Smalltalk (maybe Squeak), rather than the BASIC, C++, and C# that I started with. (C++ was too complicated. BASIC is maybe too primitive by modern standards, although assembly might have been worth learning early. C# was better but had too much ceremony for even a simple Hello World.) I might also tell myself to actually read the textbooks rather than just watch lectures.

There are so many details one has to get right in one's head to program at all, that non-programming experience doesn't prepare one for. E.g. the assignment operator isn't symmetric like the equality boolean operator (in most languages). This is not how it works in math. The simpler the language you start with, the easier it is to model in one's head.

Having a simple language with a REPL is super useful for getting this straight--if you don't know what it does, you quickly test the assumptions. Go through lots of small examples. Have the students predict and write down what the output will be, then run it and have them explain why they were surprised. This should help you diagnose where their mental models are wrong. Tell them to assume the bugs live in the programmer's mental model, not in the compiler. Flip the classroom if you need more time for this. (I.e. pre-record the lectures, and have them watch them as the homework, and work on the exercises during class time.)

Explain the language's memory model. What lives on the stack or on the heap? How are arguments passed? What's a copy and what's a mutation? Diagram on the blackboard. Write assumptions down. Human working memory is extremely limited. The gifted students might have seven registers to work with, when they're concentrating. If they're learning the language itself, or talking to you at the same time, there isn't much left to program with. Those with more average IQ might not have anything left at all. Have them start with pseudocode, and iteratively break it down to the level that it can be mechanically translated into the language. Offload everything you can.

You don't have to go it alone. Hissp does have documentation (which is pretty thorough) if you want to try, but there's also a community chat on Gitter/Matrix: https://gitter.im/hissp-lang/community

If you know how to do it in Python (or Hy, probably) the community chat can help show you how to translate it to Lissp.

The Lissp REPL also shows the Python compilation before evaluating it, so if you're already familiar with Python, that can help you get a handle on Hissp.

The misleading part wasn't from me. I'm trying to correct a common misconception here. Both "multiple" and "lines" are wrong.

Lambdas can't have single statements either. The body is only an expression. So why are we saying "multiple" (a word to distinguish from "single") if you meant to multiply statements? The number of statements is zero.

Does a try/except fit on one line? That's a try statement. Does a class? Technically possible, but typically no. That's a class statement. It's not just the "class" word, or the first line. The class statement includes its body. Many Python statement types can't fit on one line, and many others don't have to. So why are we saying "lines" to mean statements when these are not remotely the same thing?

The statement/expression distinction is a holdover from FORTRAN. Statements are just expressions that don't return a value. (Yes, Smalltalk and Haskell can implement control structures with expressions just fine, thank you.) Many functional languages do away with the distinction altogether and just use expressions. You only really need lambdas in Python for the functional style, and in functional style, expressions are all you need!

I think language popularity in industry mostly comes down to path dependence[1]. It doesn't say as much as you seem to think.

A few approaches got lucky in the rapid inflationary period of the personal computer revolution (C), and the advent of the Web (Javascript), and became deeply entrenched in industry, while superior alternatives that had been known for decades missed the boat. Industry languages still haven't caught up to where Lisp, Prolog, Smalltalk, and APL were in the 1970's, but they are clearly (if slowly) trending in that direction.

APL and derivatives are still used extensively in finance, a highly competitive field, to say the least. That's where you find the jobs.

[1] https://en.wikipedia.org/wiki/Path_dependence

No, it was rhetorical, because it's obviously (to an APL-family programmer), not bad!

Your cultural prejudice is showing. There are good reasons APL is written the way it is, and this example is simply bringing those benefits to C by writing it in the dense APL style. There are other APL derivatives, like J[1] that are written in C the same way. These projects are well-maintained. They aren't collapsing under a load of technical debt. The style works. To them, it's clean code.

[1] https://github.com/jsoftware/jsource

What? No it isn't! You didn't parse that correctly.

The query params were never in the lambda to begin with. Python function calls have strict (not lazy) semantics, i.e. "applicative order", i.e. both expressions passed as arguments to map() are evaluated before the map body gets them as parameters, thus the query params would only be evaluated once, even when inlined as they were originally.

Same with the lambda definition: it's evaluated only once. It's just the lambda body that gets reevaluated each loop, and only evaluated for the first time on the first loop.