"Declarative configuration management systems like Consfigurator and Propellor share a number of goals with projects like the GNU Guix System and NixOS. However, tools like Consfigurator and Propellor try to layer the power of declarative and reproducible configuration semantics on top of traditional, battle-tested UNIX system administration infrastructure like distro package managers, package archives and daemon configuration mechanisms, rather than seeking to replace any of those. Let’s get as much as we can out of all that existing distro policy-compliant work!"
Puppet has been doing this for over 15 years. Declarative config management is great and I love it. Unfortunately, it doesn't solve all administration problems as some software assumes an imperative installation or upgrade process.
An awful lot of 3rd party "enterprise" systems have ancient, GUI installers. Particularly ones on Windows, although there are also occasional examples of this kind of silliness on Linux.
One timecard system we ran deployed a WAR in JBoss, but the associated DB schema upgrades were hand-compiled into a Java GUI with literally no externally-scriptable control surface.
Many popular tools are declarative eg: terraform, kubernetes, graphql, ansible, etc.
It would be good to see more lisp/prolog solutions to this. It's super clunky the way terraform hcl added loops, or aws cloud formation added variables to javascript. What I really need is an abstract syntax tree that has code and data mixed, that can have different ways of reasoning or operating on that same information. Definitely lisp seems like a better fit, but who knows if it could ever be made as easy to use.
I don’t think it’s what you described, but if you use Pulumi your infrastructure can actually be code. If you like types you can use Typescript, but it supports other languages too
I'd like to see a system like Qubes but defined declaratively rather than in a GUI. The Qubes templates are sorta declarative through a system called Salt but the OS as a whole (as far as I can tell) is not. I tried getting a NixOS VM running in a NixOS host, all declaratively described and pushed to a machine, but I never could get it working with that extra layer. I'll have to try it with Consfigurator.
“Qubes-like VM-based isolation with declarative configuration” is what Spectrum[1,2] tries to build on top of Nix. It’s in active development, but doesn’t seem to be particularly usable yet.
Can someone help me understand the benefits of a Lisp or Lisp-like language? To me they feel overly verbose and make it more difficult to read code. What is the point of all the parentheses? I get that other languages have some weird syntax, but Lisp seems masochistic. Is there some actual advantage or purpose to it?
Lisp code is written in those parenthesis because in lisp, that is how you write a list. This means that your code is data that you can easily compute.
It's trivial in lisp to quote some code and operate on it, also it means the macro system looks a lot like writing "regular" code.
This opens up programming paradigms such as language extending, DSLs and meta programming (writing programs that write programs) that are clumsy, difficult or impossible in other languages.
When someone says "In Lisp, everything is a list" ... They really mean everything
I really don't see the advantage of C++. To me it feels verbose and the code is difficult to read, especially templates! What is the point of all that syntax? Is there some actual advantage or purpose to it? :) (Types, yes I know...)
More seriously. :)
The parens are definitely necessary. Think of it as sort of indentation too? Taking a typical factorial and just making up some kind of language which just uses indentation and infix notation, I mean, they're pretty similar? But the nice thing about lisp is that zerop, -, factorial are all equivalent and in the same place in the expressions. You could remove all the parenthesis and just use indentation. If you want to introduce strong typing, you can do that too.
(defun factorial (x)
(if (zerop x)
1
(* x (factorial (- x 1)))))
def factorial (x)
if zero? x
then 1
else x * factorial(x - 1)
Mentally, the parenthesis go away when you get used to them, and that happens pretty quick because there isn't any syntax to worry about. In many ways, Lisp is the simplest possible language that can do useful things. It's a thin layer on top of lambda calculus, and the early versions of lisp were more like machine language (CAR, CDR are left over from this history) but it's survived so long with almost no changes because it's pretty much the ur-language, spanning high level and low level abstractions. I expect almost any useful feature from another language could be implemented in lisp.
One benefit is that code == data. It lends itself to all kinds of meta-programming fun, the REPL, etc. The parenthesis become invisible to the reader after a while and for me, the difficulty in understanding lisp code is not the parenthesis at all, but knowing the behavior of the different special forms and macros and functions available in common-lisp (read the documentation for LOOP sometime for a good time).
As that chapter describes, LOOP is a DSL just for doing "looping things", of which there are a lot! But it's implemented as a macro, not a special keyword that can only do one boring thing.
(loop for i in *random*
counting (evenp i) into evens
counting (oddp i) into odds
summing i into total
maximizing i into max
minimizing i into min
finally (return (list min max total evens odds)))
I'm following the Common Lisp tutorial that was posted here on HN a little while ago, and the section where it goes over the little loop DSL made me take a step back and reconsider! It's pretty wild. I'm definitely starting to see the beauty of it all though.
i would also like to add that the benefit of doing it in a lisp like Common Lisp is that you get Smalltalk-type interactive development environment (if you want to see how cool this can be on a system level try StumpWM, fire up SWANK, and live-hack your window manager), AND a language with implementations (CL is an ANSI language specification abstracted from any one implementation) that have C-level benchmark speed, eg. SBCL
It’s pretty complicated to walk a Python AST — lots of new concepts to learn, not very intuitive compared to the language, and even harder to use if you want to modify the tree. The Python one is one of the nicer examples!
In a lisp like language, the language syntax itself is the same as the data structure syntax. Because these two universes align, you can do clever things with the language because it is as easy to thing in terms of the language syntax tree as it is to write code in the language itself. It makes it trivial to create new domain-specific-languages / meta-languages that make it faster to write code to solve a particular class of problems.
There are two downsides though. First, it is cumbersome to get used to writing you program in a data structure. Certainly not as cumbersome as, say, writing it in XML (like the language XSLT does) but still pretty cumbersome.
Secondly, the allure of meta programming means that it’s very easy to create a code base that isn’t intuitive to another programmer, even if you both have a lot in common already. You might define a handy log function that you use a lot called “chip”. The other person had the same good idea for the same good abstraction and they called it “twig”. You get used to writing chip a lot. They do the same with twig. It feels weird to use each other’s paradigms, even though you were both correct in abstracting out this clever logging thing that was lacking in the standard library.
Lisp ecosystems suffer from this a lot. Moving between codebases is like moving companies, each with a time consuming onboarding process relating to the house style.
Contrast this with Python where there aren’t that many Python implementations that have wildly divergent standard libraries. (MicroPython springs to mind as the only example, off the top of my head, as something that looks like standard Python but is missing some key things.)
The verbosity of Lisp is one of its biggest draws for me.
It means that I can easily read and understand what's going on in a program I've never seen before, or in my own programs after I've been away from them for a while. This is doubly important for me, as I jump between programming languages a lot.
In other, more terse languages, getting back up to speed is a lot harder for me, as they use a lot of shorthand that I forget after being away from them for a while, but with Lisp spelling things out by default, reading it is a lot easier for me.
This increased readability also makes for much easier management of complexity. I can build on a readable foundation to make a more readable larger program as well.
At the opposite side of verbosity you find the terseness of regular expressions and conventions favoring the one or two character variable names and operators of languages like Haskell (not to mention various esoteric languages deliberately designed to be difficult to program in). I can understand the appeal of this sort of compression, and sometimes it's useful for little programs, but for me they tend to lead to a write-only style that's too high a price to pay unless I'm doing nothing but programming in that one terse language constantly so I never forget what all that line noise means.
I generally value simplicity, clarity and spelling out exactly what one means over terseness and cleverness, and that's a big reason why I prefer Lisp (and especially Scheme, which is the simplest and most elegant Lisp dialect that I know of).
As for parenthesis, they make it a lot easier to reason about what's going on in the program. Instead of the language forcing the programmer to do the work of figuring out what expressions apply to what, in Lisp it's clearly spelled out for you so you know exactly what's going on by the parenthesis. It just makes programs a lot clearer, and it also makes the implementation of other language and editor features easier, as it removes a lot of ambiguity in the code.
Consfigurator relies on homoiconicity for starting up Lisp images on remote hosts and giving them instructions. The user's specification of what configuration to apply to a host is basically just Lisp code and this can be trivially serialised and deserialised.
"Declarative configuration management systems like Consfigurator and Propellor share a number of goals with projects like the GNU Guix System and NixOS. However, tools like Consfigurator and Propellor try to layer the power of declarative and reproducible configuration semantics on top of traditional, battle-tested UNIX system administration infrastructure like distro package managers, package archives and daemon configuration mechanisms, rather than seeking to replace any of those. Let’s get as much as we can out of all that existing distro policy-compliant work!"