There are many causes why function invocations with the same parameters yield different results, such as functions returning time-stamps, generating random numbers, performing I/O, accessing global variables. These causes are called side-effects in the functional programming community.
Because C (and many other commonly used programming languages) allow these side-effects to be programmed, they lack referential transparency , meaning that functions cannot be replaced by its value without changing the behaviour of a program.
which apparently has functions and …
‘Most jq builtins are referentially transparent, and yield constant and repeatable value streams when applied to constant inputs. This is not true of I/O builtins.’ - jq Manual (development version)
jq wasn’t designed as language from beginning. It is simple when query is simple, but you quickly dive into quirks when your query is out of original jq scope. Nerveless, it’s a nice tool and I made a Nix equivalent some time ago, nixq (nixq - jq but with Nix syntax · GitHub). To be fair, my approach isn’t performant at all (it chokes on large inputs).
This is a good idea. I would consider making a Racket dialect (a language implemented within the Racket language) for each aspect of Linux configuration. You can make dialects that mimic other languages, too, so even Nix could be encoded in it.
There is a lesser-known language called REBOL that uses the same idea. It is well known for having highly-expressive code. It is focused around making domain-specific languages that are very intuitive for their respective jobs; yet all of the languages are implemented under a single tool-set.
Rebol is a lightweight programming language. Rebol’s unique design makes it more productive than other language technologies. The leverage comes from Rebol’s unique blend of domain specific sub-languages called dialects. Learn more.
Video: The dramatic simplicity and productivity of Rebol code:
Didn’t we invent Nix to avoid this? This increases the need for admins to memorize commands. Nix-lang is supposed to put a stop to the ever-expanding ever-changing list of configuration commands in distros and the need to memorize config file-paths for every piece of software running on the system.
The extensibility of the configuration files also makes it impossible for a program to know where the packages should be inserted. The primary beauty of NixOS is in the fact that the user performs changes on a visual representation of the internal state of the system, and then the build command reflects those changes in the system state. This makes it more debuggable, if something goes wrong, since a ‘diff’ can be computed between old versions of the system and new versions.
I would recommend Racket. It is a language that is focused on making dialects (new languages inside the language). You can imitate other languages or make domain-specific languages. You can extend Nix language, etc, and have all of these dialects compile using the same tool-set. Racket is a one-stop-shop for programming. The biggest problem with learning a new language isn’t usually the language, but learning all the tools for it, and libraries. This puts a stop to that nonsense by letting all languages compile under one tool-set.
Also, most Lisps (if not all?) evaluate eagerly. That means that the use of such language in a domain where lazy evaluation is paramount to the execution model, is very counter-intuitive and confusing.
… by default, as lazy evaluation is easy to get upon request (in many various forms).
That means that the use of such language in a domain where lazy evaluation is paramount to the execution model, is very counter-intuitive and confusing.
Lazy execution is not actually paramount to the problem domain, and the way how lazy evaluation is used in Nix does have a bit of «when you have a good hammer, all the problems look like nails» flavour — Nix is a purely functional language, so building everything out of fixpoints is natural for Nix as it currently exists.