Hacker News new | ask | show | jobs
by bradrn 984 days ago
Since first reading it, I’ve come to disagree with this post. For personal projects, my main language is Haskell, which Hague counts as a ‘puzzle language’. But that doesn’t match my experience: if I know the problem domain, I can write a solution very fluently in Haskell. (If I don’t know the problem domain, of course, it’s difficult in any language.) I find Haskell as easy to write programs in as Python, if not more so.

On the other hand, there are some other languages I find baffling. For instance, C++. Whenever I have to use C++, I find it horribly confusing. It takes me considerable effort to figure out how to structure my program in such a way that the compiler won’t, for instance, insert a destructor call before I’ve used an object. Or that I won’t run into any one of the considerable number of footguns C++ contains. This is a language I find truly puzzling.

For this reason, I suspect that what is a ‘puzzle language’ is mostly to do with what you’re familiar with and the way you think. For me, C++ is a puzzle language. For Hague, Haskell is a puzzle language. For both of us, J is a puzzle language — but I can easily imagine someone who can write programs easily in J.

11 comments

Same. I struggle to write concise and complex code in Python. I often think of a problem in a functional sense, and would like to just map/filter/reduce and pipe my way out of it. With python I feel constrained by what the language gives me. Useless lambdas, list comprehensions that quickly become hard to grok, stdlib and syntax that forces you to wrap things like reduce(map(filter(iter))) instead of iter | filter | map | reduce.

I'm always in awe when I see the Advent of Code solutions from Norvig in Python, they often seem so elegant. But my head isn't wired to think of the problems that way.

It turns out that if your main paradigm is X then writing a solution in paradigm Y is a puzzle, as you have to convert things in your head from a natural representation to a different one. Writing performant C++ has genuinely become somewhat difficult after working in a semi-pure manner for a long time, despite C++ being my first and main language.
> It turns out that if your main paradigm is X then writing a solution in paradigm Y is a puzzle

Exactly. The entire blog post is a long way to say 'I am accostomed to think in C-derived languages'.

Of course a new language paradigm will be a puzzle, it takes a while for our brains to change/match the new paradigm.

The 'puzzle' aspect of the language isn't necessarily permanent.

Perhaps, but there are languages that obviously differ from the "general" paradigm, such as stack programming. I guess if you only ever do stack programming, "stack programming" is just programming, but obviously stands out over all languages.

The article distinguishes between prog-lang specific puzzles and "programming in general is a puzzle", but without a universal paradigm it's not clear what that is - for example, stateless functional programming might be a puzzle, but the "norm" requires memory/state management as a puzzle; imperative/declarative is the same - which imperative is the norm, it's not clear to me it's less of a puzzle to have to explicitly think about sequence and state change.

I think it is not that simple. The OP seems to have worked with different programming language and paradigms. It also has to do with the type of problem domain you have to deal with. For some type of problems, functional languages are great. For other types, they are simply not.

In my experience things get 'complicated' when you have to deal with a distributed system where multiple actors are querying and changing a shared state. (And that shared state can be stored in one or more databases and/or in files in a file system.)

I disagree with this part "If I don’t know the problem domain, of course, it’s difficult in any language."

The main benefit of non-puzzle languages is incremental progress - even when I am not solving the entire problem, I am building functions and data structures which can be used to both understand the problem domain better and eventually to construct a complete solution. Sure, that might lead to an initial inefficient solution and require some rewriting, but often it's "good enough" (tm). That is why scientific Python is so successful, even though the final result is usually a patchwork of poor choices held together by duct tape.

Some languages map objectively better on that paradigm, independent of personal experience or ease of use.

I agree that haskell does not sound like a puzzle language to me even though i do not use it. Forth however sounds like a puzzle language to me. Probably because you have to completely shift your paradigm to solve the problem. It does feel a bit like those toy language you play with in certain games for example:

https://store.steampowered.com/app/370360/TIS100

The more the language shatters your pre-existing assumptions the more it looks like a puzzle.

i would like to see an example of how the c++ compiler destructs an object before you use it. the only reason for this to happen that i can imagine is not understanding the concept of scope.
This could happen any time you return a pointer to a variable with automatic storage and then later attempt to dereference the pointer and do something with the value. Of course, you shouldn't do that, but the C++ compiler won't stop you. 'Scope' can have various meanings, but merely understanding how lexical scoping of variables works is not sufficient to understand why you shouldn't do that.
well, let me rephrase "scope" as "lifetime of objects"
Ok, but then what you're saying is almost tautological. Indeed, you won't be surprised when an object is destroyed in C++ if you understand how object lifetimes work in C++.
As I recall, the issue in my case involved a default copy-constructor which destructed an object wrongly. I’ve since learnt to delete the implicit methods of a class, but I still find reasoning about copy and move semantics to be thoroughly puzzling.
i would still think this is a misunderstanding of scope. and you really don't want to be worrying about move semantics unless you are a performance maniac, a library writer, or (most likely) both.
{ std::string s; }
see "scope" in my original comment
I am such a person! I make J videos at http://youtube.com/@tangentstorm (many of them are recordings of live-coding on a single J application), work professionally in another array language called K, and also use forth (one of his other puzzle languages) for various things (currently working on a forth-like scripting language for an animation tool, for example).

I would definitely categorize J as having a strong puzzle culture. Many of the people who use it are just doing it for recreation and to stretch their brains, and insist on writing everything in "tacit" (J's version of point-free) style.

Personally, I'm more interested in building things. Most of my J and K code look like any other scripting language, but just very highly compressed.

I would agree that Haskell is not quite in the same category, and don't get the sense that Haskellers strongly favor a particular brand of bending over backwards to make things happen. But then again I'm not nearly as tuned in to the Haskell community, and he was writing this 14 years ago...

C++ is definitely the most used puzzle language.

It is masked by the fact it is based on C which is non-puzzle. So you can always drop to get things done layer.

This article (and your counter) feels to me like a higher abstraction level of the all too common code "readability" argument. The language isn't necessarily a puzzle language any more than this or that code-segment isn't less readable. It's all just more or less familiar to the reader. Language readability is MOSTLY on syntax or small bits of idioms and how expressions are put together. This article is just another level up from that.

"readability" is an aspect of the reader, not the code.

I agree. Puzzle languages are only puzzling until you mind-meld with the language. TFA is right that non-puzzle languages are easier to get going with, at a [steep] price anyways. The problem with TFA is that it doesn't really address that price.
It's like someone encountering chopsticks for the first time and declaring them a puzzle utensil because they cannot find the edge to cut with.