使用 NixOS/Nix 的「最佳实践」是什么?

“现代”的意思是project-specific和lock file,也就是在项目根目录建一个flake.nix,里面内容参照模板,然后自动生成flake.lock,开发时使用nix shellnix develop

至于imperative用法,有nix profile,效果和nix-env类似,而且用法更符合惯例、更便于记忆,(据说还有别的好处,但是我从来没手动调用过nix-env,所以忘记了),应该说新命令才更适合新手入门和迁移。但是nix profile没法触发一些包的适配机制,所以还是建议尽量使用project-specific配置。我个人是用profile在NixOS上安装“非必要”应用程序,因为安装、卸载、清除历史记录都无需sudo,也可以随意使用unstable分支、自定义构建而不干涉系统主干。和flatpak结合,相当于变成Android式的应用管理策略了。

另外补充一点,关于nix命令和flake的“实验”性质,这不是由于技术不成熟、实现不稳定或设计方向不确定,而只是社区治理问题在产品上的体现罢了。实际上Nix(“CppNix”)整个软件都已经在事实上锁定在2.18版本了(更高的版本不被Nixpkgs接受为默认),开发者想不稳定都没办法,所以还是可以放心使用的。

1 个赞

最佳实践。。。就是一掀桌子老子不折腾了回到 Debian 拉倒!

Btw,Alpine Linux 和 Void Linux 可以看看,打包容易,软件包也够多。

2 个赞

就是要声明式,这样才保证一切可复现

Debian 确实稳,但是有些默认设置和用过 Fedora、Ubuntu 的用户的直觉不太相符,倒也不能说他们做的不对。

欧盟又不等于北约吧? :thinking:

  1. guix 的 channel 就是 git 加上 guile 的模组系统,非常简洁,我也没感到哪里慢。nix 的 channel 设计犯了大错误,又亡羊补牢了 flake。flake 说白了就是模组系统的拙劣模仿。只是因为 nix lang 过于简单,只能用高阶函数来模拟模组系统,带来的问题就是报错信息完全不可读。nix lang 里只有 lambda 表达式,真正实现了”只要有lambda就是函数式“这个笑话。被 guile 的真正的 module system 吊打。

  2. 官方仓库里有私有软件可不是什么好事,小心你电脑上不慎安装了私有字体,你又不小心在公开场合用到,然后你就违法了。说起来没有自由软件运动,如今你连免费的c语言编译器都用不上。你能在别的工程领域找到主流软件是免费软件的例子吗

  3. guix import 可以直接把 alpa, pypi, hackage 等别家仓库里的包转成 guix 的包,用不着 xxx2guix。

  4. guix describe 是用来查询信息的,跟锁定有什么关系。

  1. 作为通用编程语言,Guile的“真正”的模块系统就算真的吊打flake也没什么可以吹嘘的。而在包管理领域,这个模块系统的优势除了你说的错误信息,其实只是提供了“真正”意义上的代码补全罢了,而它的劣势就是仍然只能use-modules,而不能现场指定use哪些modules的哪些版本。——当然,Guix又“亡羊补牢”了inferior系统,但是它基于describe,因此也只提供了一重锁定。

  2. 这里是Emacs论坛,我觉得没必要再念诵自由软件的圣经。我只是指出当代主流PC有相当一部分无法在缺少非自由固件的前提下运行这一事实罢了。

  3. 确实,Guix自带的工具远比Nix和Nixpkgs丰富,文档更是天上地下。但是考虑整个“工具链”就不一定了,nix-community有一百多个repo呢。——当然其中很多都是ad hoc,还有些直接打脸Nixpkgs/NixOS,整合度无法与Guix相比。

  4. Guix默认从当前环境寻找channel,也就是不纯的。需要使用guix describe -f channels或者guix package --export-channels所导出的channel信息才能确保可复现的构建。而这一channel信息只支持一重锁定(commit或branch)。

2 个赞

你说的对,但只依靠自由软件你连硬件驱动都找不齐,只能强迫自己用旧硬件。绝大部分 Linux 发行版为了获得硬件兼容而引入非自由软件,即使要付出被 GNU 除名的代价。

难道你在商业场合不会检查字体么?

我2022年的时候在一台联想小新上用 linux-libre 只有无线网卡不能用,换一个支持的就好了,没有用任何旧硬件。linux-libre 在最新的硬件上完全没有问题,很多人只是被一些危言耸听骗了,从来没有尝试过。

字体问题只是一种例子,只要你电脑上安装了私有软件你的电脑就不再属于你了。哪怕你购买了那些私有软件,你也必须仔细阅读用户条款,哪些事能做哪些不能做。你不去看直接用,那你就等律师函吧,看看多少公司收到过 Qt 的律师函。

在一个只有自由软件的电脑上我明确知道我能干任何事情,用了私有软件我花了钱还处处受限。

这两天恰好遇到一个nixos的坑,24.11,nixos的configuration中可以指定displaymanager,比如:

  services.displayManager.sddm.enable = true;
  services.displayManager.sddm.wayland.enable = true;

我把sddm换成gdm,发现gdm无法启动。

services.xserver.displayManager.gdm.enable = true;

再换回sddm,sddm也无法启动了……

ps aux | grep sddm会发现有一个sddm的进程运行在root用户下,sudo kill <sddm-pid>后,sddm会被systemd再拉起,然后就可以进入图形界面了。但这就导致每次重启必须登录console,再拉起dm。

后来又发生了一些事情,我做了 nixos-rebuild boot --upgrade,结果系统没挂,但想再执行 nixos-rebuild switch 则一定会报错……正准备今晚重装回 arch :joy:

所以中间应该是出现了什么错误,导致nixos在这一点上并不能实现“可复现”。

NixOS底层还是用Bash、SystemD之类的东西实现的(其实,Guix论文的核心创新点就是用嵌入式DSL代替Nix的独立DSL),有时候这些东西运行出错不会触发Nix回滚。你的情况可能也是这个原因

1 个赞

整机私自拆机会失去保修资格。

但是你也是试了一次错才搞好的。

  1. 换个例子吧,Qt 是使用 GNU 系许可的。
  2. 知乎上被 Qt 发律师函的基本都是使用 Qt 开源版被国内代理恶心的。
  3. 此外,发律师函 ≠ 侵权,Qt 的代理方要是有十足的证据早就发传票了,这极可能就是一种广撒网+恶心人。

社区被一些人带了节奏, Eelco 迫于压力从 NixOS 基金会下台了,但个人感觉这对社区发展影响不大,Eelco 仍旧是 Nix 包管理器的 maintainer,而且他自己也说了,近年来他本来也没怎么参与 NixOS 跟 Nixpkgs 的开发。

没毛病, 但我还是想问下大概需要集齐哪些特性才称得上是提供了函数式编程?

嘛,这既然是个没有明确又权威定义的东西吧?

在当下且没有语境的情况下,函数式指的是SML、OCaml和不开扩展的Haskell。这跟流行趋势、语言之间的传承关系以及语言的普及程度有关系。

往前可能会说 ruby 是函数式,但是 ruby 过气了。现在最火的语言是 rust,rust 从 OCaml 和 Haskell 学习了 ADT、模式匹配和 typeclass,所以这些特性被当成了函数式的核心。未来新的语言流行了,别的特性又会被当成函数式的关键。

不过我不是在说函数式就是特性的集合,说 lisp/scheme 是一门函数式语言很大程度上是搞笑的。当然 common lisp 是一门面向对象语言,这无可置疑。

觉得 Common Lisp 不算还情有可原,能觉得 Scheme 还不够函数式只能说明十几页的 RnRS 标准都没读完。堪比见到 Smalltalk 名字里带 small 觉得是给小孩子用的了。我知道你想的是“Scheme 不是有 set! 么,和 Common Lisp 就是一回事”,实际上 Scheme 充许 set! 的运用不比 SML 的 := 寛松多少,同样不能直接 set! 未声明的变量,只不过比如 Racket Chez 之流在 REPL 里是 interactive 环境放松限制了,SML 能算函数式,Scheme 凭什么不能?

函数式编程总而言之,program calculation using equational style reasoning,说的俗套一点只要用不可变值和无副作用的函数就是函数式编程完全没错,不要觉得因为说”函数式编程就是用纯函数”太直白不够装比,就硬往 ADT, pattern match 上套,属于是只守了小节,失了大节

只有 lambda 的函数式语言很搞笑吗?一点也不,所谓的 ADT 定义不过是 church-encoding (当然也可以是 mogensen-scott encoding)的语法糖,typeclass 也不过是为了实现 ad hoc polymorphism。觉得只有 lambda 就看不起它,怕是连 lambda cube 都不知道。

2 个赞

没学过理论,但是我想 lambda 表达式之间也是有点区别的。像 C++ 那种 lambda 自己无法延长捕获的变量的生命周期,还有动态作用域下的 lambda 捕获的不是确定且唯一的词法变量。如果提供的是这种 lambda,算得上是函数式编程吗?

完全没有副作用以及变量命名不重复的前提(Emacs 24 以前 lexical-let 的原理)下的话,或是只能用 first order function (APL dfns 的原理) 条件下,用动态作用域还是词法作用域对函数的结果是不会产生区别的。正是因为能把 lambda 赋值给变量事后再调用,closure 能否 capture variable reference 才有关系。

影响总之没有你想的那么大,C++ 的 lambda 还是 dynamic scoping lambda,都是因为编程当中生命周期管理和副作用的不可避免导致的。编程语言用的 IO 函数会因为操作系统资源问题调用失败,它就失去当函数式编程的资格了么?不至于吧,因为就算 IO 不是严格的 Monad,它好歹有个 Monad 的介面。同理 non-capturing lambda 好歹也和 closure 够像,从实用角度就是和 closure 有类似的性质就可类似着用。

另外忘了说了,完全没有 lambda 的 point free style 也是函数式

1 个赞

而且 Guix 的社区比 Nix 小(基本只有 FSF/GNU 忠实粉、看不上任何没有得到 GNU 认可的 Linux 发行版的那种人可能去用 Guix),遇到问题得到解决所耗费的时间也会更长吧?

P.S. 谁开了“慢速模式”? :melting_face:

1 个赞