(aside from Haskell and Scheme themselves, of course)
Those PureScript records tho...
And in any rnrs complient Scheme, it's fairly trivial to make a strict functional dialect. And in Guile or Racket, it's even easier.
Unfortunately, Guix doesn't do this. Which meant Guix can't guarantee referential transparency. Although if the packager is an ANY WAY competant, it will be maintained.
No, it's not. It's a cut-down Scheme: Most of your scheme knowledge would apply directly, or indirectly.
Besides, even if it was a different language, it's a pre-existing one: DSSSL is pretty much this.
>If you're learning a new language, a new syntax isn't very hard.
Yes, but for me, the choice is learning a new language that has no other applications, save package managment, and using a subset of a language I already know.
>And there's not a terrible amount of people who think S-expressions are an inherently good syntax
I said from my perspective. I'm a schemer, so I'm already on board with sexprs.
Only if you regularly write code using purely functional scheme in the first place. The difficulty of writing in a new language is very rarely figuring out what function calls to make, at least for me - it's about thinking in terms of the language.
'((extensible-records . being-key-value-maps?))
Alists are fast enough for this, and they ARE k/v maps. And support for them is in rnrs. '(this is a list)
'((this . is) (an . alist))
Looks pretty distinct to me. '((this . is) (a . list) (of . cons))
'((this . is) (an . alist))
Hey look, my list of cons looks incredibly like an alist... funny that.and alist is a list of pairs. That's what it is. Semantically, there isn't really another reason to use the format.
They don't handle functions or infinite datastructures though.
- Guix refuses to integrate proprietary software so its usability is diminished compared to Nix (and Guix has less software packaged than Nix in the first place, AFAIK).
- Nix is a pretty good language for the task.
But this language is not a DSL, but a general purpose language that has pattern matchers, HTTP libraries, XML parsers, data structure implementations, etc.
>Guix refuses to integrate proprietary software so its usability is diminished compared to Nix (and Guix has less software packaged than Nix in the first place, AFAIK).
Guix is younger, thus has less software packaged, but the number of new packages introduced with each Guix release continues to increase. I have all the packages most important to me and have been using GuixSD exclusively for at least a year now.
>Nix is a pretty good language for the task.
The problem with any DSL is that is not very extensible and developers must spend time maintaining parsers, compilers, etc. for a one-off language. Guix is achieving its velocity in good part thanks to using an existing general purpose language that new languages can be embedded within.
I'm not expressing this as a criticism that I have, but for some people what you described is not a feature but a bug. :)
I don't know, I rather like Nix's language, maybe I am just not a Lisp person.
More practically, I can't think of anything that I wanted that Scheme offers but the nix expression language doesn't.
It may have a smaller stdlib than scheme (but I doubt it). But it's very hard to be simpler than scheme semantically.
As for what I want from scheme that nix doesn't provide, a simple, regular, syntax that I already know is what I want. I understand that that doesn't apply to everybody.
Yes, I mean the semantics of the language. Scheme is indisputably more complex. There isn't really much a standard library for the Nix Expression Language either.
> As for what I want from scheme that nix doesn't provide, a simple, regular, syntax that I already know is what I want. I understand that that doesn't apply to everybody.
off the top of my head:
Scheme-Simplified ::= <Item>*
Items ::= (define (<Id>*) <Expr>)
| (define <Id> <Expr>)
Expr ::= (<Expr> <Expr>*)
| (set! <Id> <Expr>)
| (lambda (<Id>*) <Expr>)
Nix-Expr ::= <Pattern> : <Nix-Expr>
| with <Nix-Expr>; <Nix-Expr>
| { <Nix-Item>* }
| let <Nix-Item>* in <Expr>
| <Expr> <ArithOp> <Expr>
| <Expr>.<Id>
| <Expr>.<String-Lit>
| <Expr> ? <Id>
| <Expr> ? <Id> or <Nix-Expr>
Nix-Item ::= <Id> = <Nix-Expr>;
| <StringLit> = <Nix-Expr>;
| inherit <Expr>;
| inherit (<Nix-Expr>) <Nix-Expr>; Scheme ::= <Expr>*
Expr ::= <Atom>
| (<Expr>*)
Atom ::= <String>
| <Symbol>
| <Number>
And IIRC, that's close to what r5rs requires, although without the '`, syntactic sugar, which a readtable would handle in schemes that have them, and would be added to the above for schemes that don't. I may be wrong, though.The semantics are also simple:
A function's arguments are evaluated, bound to arguments and passed to it. A special form or macro have their arguments passed to them unevaled. In the case of a macro, the output of the macro is evaled instead. Scope is lexical.
There's about 95% of the semantics right there. The only things I left out, to my knowledge, are dynamic variables, which weren't standardized until recently.
The entire thing may be larger than Nix (I don't think it is), but more regular? I doubt it.
Besides dynamic variables, there is also plain old variable mutation. Scheme macros are much more complex than what you described, because of hygiene. For the sake of making Scheme look better, I left macros out of my grammar. The Nix expression language has none of these things.
> but more regular? I doubt it.
Nix's lack of a top level (the <Items>* in Scheme) is a big boon for simplicity, especially concerning imports from other files which I forgot to include.
Fair enough, but:
>I should take a look at the guix APIs to craft a bigger subset.
What? No.
Those don't add any complexity to the language. You don't add every function to your BNF syntax, do you? This is what I meant about regularity: The sexpr and atoms are the only syntactic elements (except quote and friends, which are syntactic sugar for sexprs).
Most of the things you included in your scheme BNF syntax aren't syntax, they're special forms. Special forms are not syntactically distinct, they are semantically distinct. So while define, if, and lambda are part of the semantics, they aren't part of the syntax.
Macros, too, have no syntactic differentiation: You actually CAN'T add macros to the BNF of the syntax, because there is no syntax to add.
If that's not regular, I don't know what is.
>Nix's lack of a top level (the <Items>* in Scheme) is a big boon for simplicity, especially concerning imports from other files which I forgot to include.
How? What's so complex about having multiple forms at toplevel?
Oh, believe me, I'm all about the separation between language and library. I mean the smallest subset of Scheme necessary to use the api. For example, it might use string maps instead of association lists.
> Most of the things you included in your scheme BNF syntax aren't syntax, they're special forms.
This is just terminology. We have a hierarchy of languages here:
1. All terminating Scheme programs are Scheme programs
2. All Scheme programs are valid s-exprs
3. All s-exprs are plain text
4. All plain text is valid bytestring.
...
> Macros, too, have no syntactic differentiation: You actually CAN'T add macros to the BNF of the syntax, because there is no syntax to add.I was doing a grammar for scheme programs, not anything else on that list. Macros invocation requires its own non-terminals because its arguments are arbitrary sexprs, not merely unevaluated expressions.
> How? What's so complex about having multiple forms at toplevel?
Imports. file=expression makes Nix's `import <some-path>` dead simple. Scheme's is necessarily more complicated.
Look, first off, in a scheme system, there's no reason to use string maps. Symbols or strings can be used for alist lookup, and alists are plenty fast for these purposes.
Secondly, this is how a scheme experession is run, AFAIK.
(define foo (map odd? '(1 2 3 4)))
First off, in a scheme that has it, the readtable is run, transforming shortcuts like '<expr> into (quote <expr>). Then the expression is parsed into a memory representation of a sexpr. This could be a series of cons cells, but a lot of schemes use something else. What happens next is pretty implementation dependant, but in an interpreter, the resultant expression is evaluated. The evaluator sees the define - note this, in your model, the parser would catch this - dectects that it is a special form, and passes the expr to the code handing define. That code then evaluates the cddr of the expr, and binds the result to the symbol in the cadr. In some implementations, the cadr can be a list, but this isn't standard.Note that all the parser did was translate some syntactic sugar, and give the interpreter the datastructure representing the sexpr. Because that, AFAIK, is all the parser does.
I could be wrong, but tell me if I am, don't just go on as if I'd said nothing.
>I was doing a grammar for scheme programs, not anything else on that list. Macros invocation requires its own non-terminals because its arguments are arbitrary sexprs, not merely unevaluated expressions.
...An unevaled expression IS an arbitrary sexpr. What else can it be?
Using pre-compiled binaries means that builds aren't reproducible, a goal of both Nix and Guix.
M-x passive-agressive-mode
And now, I'll go upgrade my NVIDIA drivers, and load up Psychonauts on Steam.The same way: cryptographic signatures and checksums.
For example, the Haskell toolchain in nixpkgs downloads pre-compiled binaries of old GHC versions (7.0.4 and 7.4.2) which it uses to bootstrap the newer versions.
The binaries are checksummed to ensure reproducibility.
Binaries can be signed to prove that the chain of trust is unbroken between the vendor (who maybe you trust enough to run their software on your systems) and you. In the case of a system with reproducible builds, that signature also says, "if you were to build this yourself, you'd end up with the same binary I am sending you."
Edit: I am beginning to realize that when davexunit says "pre-compiled binaries" they are not talking about an OS vendor (like Guix) distributing a binary package (with source available). They are talking about binary blobs provided by third parties, and in a form that is not reproducible, such as an nvidia driver kernel blob. This has led to me assuming davexunit is nuts, but apparently it is just that neither of us has been speaking very clearly to each other, and thus we've seemingly been talking past each other.
[0] https://reproducible-builds.org/
[1] https://www.gnu.org/software/guix/manual/html_node/Bootstrap...
Every binary in the chain can be signed and reproducible (theoretically; we aren't quite there, realistically speaking, and the bootstrap, as you note, is tricky). Forcing every user to build everything from source every time is just a mess, and provides little benefit over signed (reproducible) binaries for the vast majority of users.
It sounds like you (and the guix project) are conflating two orthogonal concepts and making "reproducible builds" into a concept that won't work in widespread use, and maybe even has negative value. We want reproducible builds so that we can be certain that the binary a vendor ships us is built exactly the way they say it was. We don't want it so that everyone is forced to build everything from scratch every time.
Reproducible builds means we can build an identical binary from source to prove that it is what we think it is. It should not mean we must build an identical binary from source every time we install a thing.
>We don't want it so that everyone is forced to build everything from scratch every time.
I believe it is you who is confused. I never suggested this is what reproducible builds are about.
https://www.gnu.org/software/guix/manual/html_node/Substitut...
SwellJoe: Go back and substitute "source verifiable" every time davexunit says "reproducible" and everything he says makes sense.
davexunit: Read everyone else's comments from the POV where "reproducible" mean "reliable bitwise replication" without consideration of scientifically reproducible experiments or source verification, and everything they say makes sense.
I interpreted your statement of "Using pre-compiled binaries means that builds aren't reproducible, a goal of both Nix and Guix" to mean, "Guix does not distribute pre-compiled binaries, because they can't be reproduced". That still seems an entirely reasonable interpretation of that sentence, to me, as someone with no familiarity with Guix.
But, I now see that your intended meaning was that Guix does not distribute stuff like nvidia blobs, or Flash player, which is a perfectly reasonable choice for them, and nothing less than I would expect of a GNU project (and Fedora, my current favorite desktop distro, has the same policy, so I don't have a problem with it).
We don't want this either :) Let's not boil the oceans.
Nix and Guix are both a hybrid of build-from-source and binary package management systems. The package recipes and management tools describe how to build some software from source, and then transparently provide binaries for those recipes when the binary is available from a user-approved provider of the binaries.
But, by providing the full build recipes, all the way down to the bootstrap, users can easily rebuild binaries from source to check that their selected binary provider is honest, or to find reproducibility bugs.
In the case of a package recipe for some software that does not have source code available (a binary "blob"), the recipe would just download the blob from somewhere. We don't package those things in Guix, whereas Nix does. Although, it's not hard to make custom recipes that would do that, if you wanted to.
I have no problem with Guix being ideologically pure. Only with the notion that you can't have a reproducible build without forcing everyone to build it it themselves, which it seems is not the case with Guix. Cool.
https://github.com/genenetwork/guix-bioinformatics
and
https://github.com/Ecogenomics/ace-guix
I'm not sure how easy it is to maintain a system with extra packages like this, but it'd be nice to be able to use an "overlay" repo as you can in Gentoo for personal/custom packages.
Would love to ping davexunit to see if he can elaborate, because I don't see any specific way to add repositories from the documentation.
Is something similar/comparable planned to be added?
Orrr should someone step forward and volunteer to add it as a feature...?
(Don't worry, it's just a tiny toy gun.)
Although I do think that programmers often tend to try to solve problems with the kind of tools that they like to make, rather than ones that would be appropriate for the user -- and that's why the *nix open source world has so many incompatible programming languages and configuration formats, and so few good GUIs.
Use TOML, JSON, or YAML. If you need something general purpose, use Scheme. It works well embedded.