History of changes to
‘You can write nicer nix code’

2025-09-02





> 2025-04-17: Add rights to post and notes, see 61ee3af

diff --git a/post/you-can-write-nicer-nix-code.md b/post/you-can-write-nicer-nix-code.md
index 0916a15..e8cb6e8 100644
--- a/post/you-can-write-nicer-nix-code.md
+++ b/post/you-can-write-nicer-nix-code.md
@@ -4,6 +4,7 @@ date: 2025-02-21
 lang: en
 description: "You can write nicer nix code"
 keywords: nix
+rights: CC BY-NC-SA 4.0 Jiri Vlasak
 ---
 
 Don't get me wrong. You can't write *nice* nix code, because [Nix




> 2025-04-16: Add meta to you can write nicer nix code post

diff --git a/post/you-can-write-nicer-nix-code.md b/post/you-can-write-nicer-nix-code.md
index 136924a..0916a15 100644
--- a/post/you-can-write-nicer-nix-code.md
+++ b/post/you-can-write-nicer-nix-code.md
@@ -1,6 +1,9 @@
 ---
 title: "You can write nicer nix code"
 date: 2025-02-21
+lang: en
+description: "You can write nicer nix code"
+keywords: nix
 ---
 
 Don't get me wrong. You can't write *nice* nix code, because [Nix




> 2025-04-16: Revert "Extend warning post with you can write better"

diff --git a/post/you-can-write-nicer-nix-code.md b/post/you-can-write-nicer-nix-code.md
new file mode 100644
index 0000000..136924a
--- /dev/null
+++ b/post/you-can-write-nicer-nix-code.md
@@ -0,0 +1,396 @@
+---
+title: "You can write nicer nix code"
+date: 2025-02-21
+---
+
+Don't get me wrong. You can't write *nice* nix code, because [Nix
+language is ugly][1]. In my opinion, of course. But sure you can do
+better.
+
+[1]: https://qeef.srht.site/post/warning-nix-language/
+
+Here are some suggestions:
+
+- Make nesting match the scope.
+
+- Name things and name them properly.
+
+- Let things in `let ... in ...` follow order.
+
+- Only use anonymous function when it fits a single line.
+
+- Either fit a function call with all the arguments at a single line, or
+  put each argument at new line with the same indent as called function.
+
+
+We use Nix at work and so I need to understand it. When I am trying to
+find out what happens in our `flake.nix`, I do refactor the code. Some
+of the source code of a template we use [is published][2] so I believe
+it's ok to share my findings about that part of code.
+
+[2]: https://gitlab.com/Cynerd/flakepy/
+
+For the purpose of this post, the goal of our `flake.nix` is to
+`buildPythonPackage` and provide `devShells` with the dependencies.
+We use data from `pyproject.toml`, stored in the `pyproject` variable:
+
+``` nix
+pyproject = nixpkgs.lib.trivial.importTOML ./pyproject.toml;
+```
+
+Now, the main problem our flake solves -- we take Python package names
+from the `pyproject.toml`, but these names correspond to the Python
+package names in PyPI and it may happen that the same Python package has
+different name in Nix. Like `SQLAlchemy`.
+
+I will provide only interesting parts of our `flake.nix`.
+
+``` nix
+pypi2nix = list: pypkgs:
+  attrValues (getAttrs (map (n: let
+      pyname = head (match "([^ =<>;~]*).*" n);
+      pymap = {
+        "SQLAlchemy" = "sqlalchemy";
+      };
+    in
+      pymap."${pyname}" or pyname)
+    list)
+    pypkgs);
+
+requires = pypi2nix pyproject.project.dependencies;
+
+buildPythonPackage {
+  dependencies = requires pythonPackages;
+  # ...
+
+devShells.default = pkgs.mkShell {
+  packages = with pkgs; [
+    ruff
+    (python3.withPackages (p:
+      [p.build p.mypy]
+      ++ foldl (prev: f: prev ++ f p) [] [
+        requires
+      ]))
+    # ...
+```
+
+I like it so much. Let's understand what is going on here, starting with
+
+``` nix
+pypi2nix = list: pypkgs:
+  attrValues (getAttrs (map (n: let
+      pyname = head (match "([^ =<>;~]*).*" n);
+      pymap = {
+        "SQLAlchemy" = "sqlalchemy";
+      };
+    in
+      pymap."${pyname}" or pyname)
+    list)
+    pypkgs);
+```
+
+The first line is
+
+``` nix
+pypi2nix = list: pypkgs:
+```
+
+saying that `pypi2nix` is a function of two arguments, `list` and
+`pypkgs`.
+
+``` nix
+  attrValues (getAttrs (map (n: let
+```
+
+`attrValues` takes attribute set and returns the list of values -- it
+drops the attribute names. Its argument is attribute set
+`(getAttrs ...)`.
+
+`getAttrs` takes a list of strings of attribute names as the first
+argument `(map ...)` and some attribute set as the second argument
+`pypkgs`. It returns the attribute set containing attributes (names and
+corresponding values) from the second argument `pypkgs` with the
+attribute names from the first argument `(map ...)`.
+
+`map` is higher-order function. It takes a function `(n: ...)` as the
+first argument and a list `list` as the second argument. The `map`
+generates new list by applying function in the first argument to each
+element of the list in the second argument.
+
+`n: let ... in ...` is a function. In `let ...` it prepares variables it
+uses and in `in ...` there is the implementation. `let ...` contains:
+
+- ``` nix
+        pyname = head (match "([^ =<>;~]*).*" n);
+  ```
+
+  This piece of code takes first characters of `n` (the function's only
+  argument) that are not ` =<>;~` and stores them in `pyname` variable.
+  It converts `SQLAlchemy>=2.0` to `SQLAlchemy`.
+
+- ``` nix
+        pymap = {
+          "SQLAlchemy" = "sqlalchemy";
+        };
+  ```
+
+  `pymap` is mapping of Python package names used in PyPI to names used
+  in Nix.
+
+The function implementation, i.e., what function returns, is in
+`in ...`:
+
+- ``` nix
+        pymap."${pyname}" or pyname
+  ```
+
+  If `pyname` is in `pymap`, return the corresponding value. If not,
+  return `pyname`.
+
+So far so good.
+
+``` nix
+requires = pypi2nix pyproject.project.dependencies;
+```
+
+The interesting part about `requires` is that `pypi2nix` is partially
+applied here: `pyproject.project.dependencies` is a list of dependencies
+from the `pyproject.toml` and pypi2nix takes a list `list` as the first
+argument. However, `pypi2nix` takes two arguments in total, but there is
+no second argument!
+
+The result of the partial application, `requires`, is therefore function
+that expects a single argument. That single argument corresponds to the
+second argument of the `pypi2nix` function, `pypkgs`.
+
+``` nix
+buildPythonPackage {
+  dependencies = requires pythonPackages;
+  # ...
+```
+
+Here, we build the python package. `pythonPackages` are Python packages
+from Nix. In reality, this code looks slightly different, but that's not
+interesting now.
+
+Interesting is that `dependencies` are now the result of `requires`
+applied to the `pythonPackages`. This is the same as:
+
+``` nix
+buildPythonPackage {
+  dependencies = pypi2nix pyproject.project.dependencies pythonPackages;
+  # ...
+```
+
+Finally, the development shell.
+
+``` nix
+devShells.default = pkgs.mkShell {
+  packages = with pkgs; [
+    ruff
+    (python3.withPackages (p:
+      [p.build p.mypy]
+      ++ foldl (prev: f: prev ++ f p) [] [
+        requires
+      ]))
+    # ...
+```
+
+From the first line:
+
+``` nix
+devShells.default = pkgs.mkShell {
+```
+
+Create (`pkgs.mkShell`) new default development shell. The default
+development shell is run by `nix develop`. `pkgs` here is a variable
+with `nixpkgs.legacyPackages` for some *system*.
+
+``` nix
+  packages = with pkgs; [
+    ruff
+```
+
+In the development shell, the `ruff` package will be available. That
+`with pkgs;` is just a shortcut. The following has the same meaning:
+
+``` nix
+  packages = [
+    pkgs.ruff
+```
+
+We use `with pkgs;` because we usually need more than a single package.
+
+The last part lets us include Python dependencies in the development
+shell.
+
+``` nix
+    (python3.withPackages (p:
+```
+
+`python3.withPackages` is a higher-order function. It takes a function
+to which it provides the attribute set with Python packages. It returns
+the list of packages, here to be included in the development shell.
+
+`(p: ...)` is the function. `p` here is the attribute set with Python
+packages provided by the `python3.withPackages`.
+
+``` nix
+      [p.build p.mypy]
+```
+
+This is the first part of the list of packages to be returned by the
+`(p: ...)` and `python3.withPackages` function, respectively.
+
+``` nix
+      ++ foldl (prev: f: prev ++ f p) [] [
+        requires
+      ]))
+    # ...
+```
+
+This piece of code was the most challenging, to be honest.
+
+- `++` is the concatenation of the lists, so what follows `++` needs
+  also be a list.
+
+- `foldl` is a higher-order function that takes three arguments, here
+  `foldl () [] []`.
+
+- The ending `))` are to close function `(p: ...)` and function
+  `(python3.withPackages ...)`.
+
+The first argument to `foldl` is a *function*, the second argument is
+the initial value of an *aggregator*, and the third argument is a
+*list*.
+
+Generally, `foldl` goes over each element of the *list*, applying the
+*function* to the *aggregator* and the *list*'s element, storing the
+result of the *function* application to the *aggregator*. When there is
+no element left in the *list*, `foldl` returns the *aggregator*.
+
+Our *function* is
+
+``` nix
+(prev: f: prev ++ f p)
+```
+
+the initial value of the *aggregator*, here called `prev`, is
+
+``` nix
+[]
+```
+
+and the *list* is
+
+``` nix
+[ requires ]
+```
+
+We have only the single element in the list (`f` in our *function*), so
+there is just a single step and therefore `foldl` returns
+
+``` nix
+[] ++ (requires p)
+```
+
+- Recall that `p` is the attribute set with Python packages passed by
+  the `python3.withPackages`.
+
+- `( )` are here due to the precedence -- functions can be list's
+  elements, too! However, we need the result of the function call.
+
+- Yes, our *list* contains functions we apply to the attribute set with
+  Python packages to generate the list of Python packages to be included
+  in the development shell.
+
+Hypothetically, we could have `requires-doc`, the result of partial
+application of the `pypi2nix` to the list of *documentation*
+dependencies, and our list could look like
+
+``` nix
+[ requires requires-doc ]
+```
+
+In such a case, the result of the `foldl` would be
+
+``` nix
+[] ++ (requires p) ++ (requires-doc p)
+```
+
+---
+
+It's nice to find out how things work. Here is the refactored version:
+
+``` nix
+# Return a list of derivations
+# - wanted-pkgs is a list of strings of wanted Python package names
+# - available-pkgs is attribute set of all Python packages available in Nix
+pypi2nix = wanted-pkgs: available-pkgs: let
+  pypi-name-to-nix-name = {
+    # "pypi-name" = "nix-name";
+    "SQLAlchemy" = "sqlalchemy";
+  };
+  to-nix-name = pypi-name: let
+    pkg-name = head (match "([^ =<>;~]*).*" pypi-name);
+  in
+    pypi-name-to-nix-name.${pkg-name} or pkg-name;
+  nix-names = map to-nix-name wanted-pkgs;
+in
+  attrValues (getAttrs nix-names available-pkgs);
+
+requires = pypi2nix pyproject.project.dependencies;
+
+buildPythonPackage {
+  dependencies = requires pythonPackages;
+  # ...
+
+let
+  wanted-pkgs = wanted-list: wanted-fns: available-pkgs:
+    foldl
+    (wanted-pkgs: wanted-from: wanted-pkgs ++ wanted-from available-pkgs)
+    (attrValues (getAttrs wanted-list available-pkgs))
+    wanted-fns;
+in
+  devShells.default =
+    pkgs.mkShell
+    {
+      packages = with pkgs; [
+        ruff
+        (python3.withPackages
+          (wanted-pkgs
+            [ "build" "mypy" ]
+            [ requires ]))
+        # ...
+```
+
+Feel free to compare to the original code:
+
+``` nix
+pypi2nix = list: pypkgs:
+  attrValues (getAttrs (map (n: let
+      pyname = head (match "([^ =<>;~]*).*" n);
+      pymap = {
+        "SQLAlchemy" = "sqlalchemy";
+      };
+    in
+      pymap."${pyname}" or pyname)
+    list)
+    pypkgs);
+
+requires = pypi2nix pyproject.project.dependencies;
+
+buildPythonPackage {
+  dependencies = requires pythonPackages;
+  # ...
+
+devShells.default = pkgs.mkShell {
+  packages = with pkgs; [
+    ruff
+    (python3.withPackages (p:
+      [p.build p.mypy]
+      ++ foldl (prev: f: prev ++ f p) [] [
+        requires
+      ]))
+    # ...
+```




> 2025-04-04: Extend warning post with you can write better

diff --git a/post/you-can-write-nicer-nix-code.md b/post/you-can-write-nicer-nix-code.md
deleted file mode 100644
index 136924a..0000000
--- a/post/you-can-write-nicer-nix-code.md
+++ /dev/null
@@ -1,396 +0,0 @@
----
-title: "You can write nicer nix code"
-date: 2025-02-21
----
-
-Don't get me wrong. You can't write *nice* nix code, because [Nix
-language is ugly][1]. In my opinion, of course. But sure you can do
-better.
-
-[1]: https://qeef.srht.site/post/warning-nix-language/
-
-Here are some suggestions:
-
-- Make nesting match the scope.
-
-- Name things and name them properly.
-
-- Let things in `let ... in ...` follow order.
-
-- Only use anonymous function when it fits a single line.
-
-- Either fit a function call with all the arguments at a single line, or
-  put each argument at new line with the same indent as called function.
-
-
-We use Nix at work and so I need to understand it. When I am trying to
-find out what happens in our `flake.nix`, I do refactor the code. Some
-of the source code of a template we use [is published][2] so I believe
-it's ok to share my findings about that part of code.
-
-[2]: https://gitlab.com/Cynerd/flakepy/
-
-For the purpose of this post, the goal of our `flake.nix` is to
-`buildPythonPackage` and provide `devShells` with the dependencies.
-We use data from `pyproject.toml`, stored in the `pyproject` variable:
-
-``` nix
-pyproject = nixpkgs.lib.trivial.importTOML ./pyproject.toml;
-```
-
-Now, the main problem our flake solves -- we take Python package names
-from the `pyproject.toml`, but these names correspond to the Python
-package names in PyPI and it may happen that the same Python package has
-different name in Nix. Like `SQLAlchemy`.
-
-I will provide only interesting parts of our `flake.nix`.
-
-``` nix
-pypi2nix = list: pypkgs:
-  attrValues (getAttrs (map (n: let
-      pyname = head (match "([^ =<>;~]*).*" n);
-      pymap = {
-        "SQLAlchemy" = "sqlalchemy";
-      };
-    in
-      pymap."${pyname}" or pyname)
-    list)
-    pypkgs);
-
-requires = pypi2nix pyproject.project.dependencies;
-
-buildPythonPackage {
-  dependencies = requires pythonPackages;
-  # ...
-
-devShells.default = pkgs.mkShell {
-  packages = with pkgs; [
-    ruff
-    (python3.withPackages (p:
-      [p.build p.mypy]
-      ++ foldl (prev: f: prev ++ f p) [] [
-        requires
-      ]))
-    # ...
-```
-
-I like it so much. Let's understand what is going on here, starting with
-
-``` nix
-pypi2nix = list: pypkgs:
-  attrValues (getAttrs (map (n: let
-      pyname = head (match "([^ =<>;~]*).*" n);
-      pymap = {
-        "SQLAlchemy" = "sqlalchemy";
-      };
-    in
-      pymap."${pyname}" or pyname)
-    list)
-    pypkgs);
-```
-
-The first line is
-
-``` nix
-pypi2nix = list: pypkgs:
-```
-
-saying that `pypi2nix` is a function of two arguments, `list` and
-`pypkgs`.
-
-``` nix
-  attrValues (getAttrs (map (n: let
-```
-
-`attrValues` takes attribute set and returns the list of values -- it
-drops the attribute names. Its argument is attribute set
-`(getAttrs ...)`.
-
-`getAttrs` takes a list of strings of attribute names as the first
-argument `(map ...)` and some attribute set as the second argument
-`pypkgs`. It returns the attribute set containing attributes (names and
-corresponding values) from the second argument `pypkgs` with the
-attribute names from the first argument `(map ...)`.
-
-`map` is higher-order function. It takes a function `(n: ...)` as the
-first argument and a list `list` as the second argument. The `map`
-generates new list by applying function in the first argument to each
-element of the list in the second argument.
-
-`n: let ... in ...` is a function. In `let ...` it prepares variables it
-uses and in `in ...` there is the implementation. `let ...` contains:
-
-- ``` nix
-        pyname = head (match "([^ =<>;~]*).*" n);
-  ```
-
-  This piece of code takes first characters of `n` (the function's only
-  argument) that are not ` =<>;~` and stores them in `pyname` variable.
-  It converts `SQLAlchemy>=2.0` to `SQLAlchemy`.
-
-- ``` nix
-        pymap = {
-          "SQLAlchemy" = "sqlalchemy";
-        };
-  ```
-
-  `pymap` is mapping of Python package names used in PyPI to names used
-  in Nix.
-
-The function implementation, i.e., what function returns, is in
-`in ...`:
-
-- ``` nix
-        pymap."${pyname}" or pyname
-  ```
-
-  If `pyname` is in `pymap`, return the corresponding value. If not,
-  return `pyname`.
-
-So far so good.
-
-``` nix
-requires = pypi2nix pyproject.project.dependencies;
-```
-
-The interesting part about `requires` is that `pypi2nix` is partially
-applied here: `pyproject.project.dependencies` is a list of dependencies
-from the `pyproject.toml` and pypi2nix takes a list `list` as the first
-argument. However, `pypi2nix` takes two arguments in total, but there is
-no second argument!
-
-The result of the partial application, `requires`, is therefore function
-that expects a single argument. That single argument corresponds to the
-second argument of the `pypi2nix` function, `pypkgs`.
-
-``` nix
-buildPythonPackage {
-  dependencies = requires pythonPackages;
-  # ...
-```
-
-Here, we build the python package. `pythonPackages` are Python packages
-from Nix. In reality, this code looks slightly different, but that's not
-interesting now.
-
-Interesting is that `dependencies` are now the result of `requires`
-applied to the `pythonPackages`. This is the same as:
-
-``` nix
-buildPythonPackage {
-  dependencies = pypi2nix pyproject.project.dependencies pythonPackages;
-  # ...
-```
-
-Finally, the development shell.
-
-``` nix
-devShells.default = pkgs.mkShell {
-  packages = with pkgs; [
-    ruff
-    (python3.withPackages (p:
-      [p.build p.mypy]
-      ++ foldl (prev: f: prev ++ f p) [] [
-        requires
-      ]))
-    # ...
-```
-
-From the first line:
-
-``` nix
-devShells.default = pkgs.mkShell {
-```
-
-Create (`pkgs.mkShell`) new default development shell. The default
-development shell is run by `nix develop`. `pkgs` here is a variable
-with `nixpkgs.legacyPackages` for some *system*.
-
-``` nix
-  packages = with pkgs; [
-    ruff
-```
-
-In the development shell, the `ruff` package will be available. That
-`with pkgs;` is just a shortcut. The following has the same meaning:
-
-``` nix
-  packages = [
-    pkgs.ruff
-```
-
-We use `with pkgs;` because we usually need more than a single package.
-
-The last part lets us include Python dependencies in the development
-shell.
-
-``` nix
-    (python3.withPackages (p:
-```
-
-`python3.withPackages` is a higher-order function. It takes a function
-to which it provides the attribute set with Python packages. It returns
-the list of packages, here to be included in the development shell.
-
-`(p: ...)` is the function. `p` here is the attribute set with Python
-packages provided by the `python3.withPackages`.
-
-``` nix
-      [p.build p.mypy]
-```
-
-This is the first part of the list of packages to be returned by the
-`(p: ...)` and `python3.withPackages` function, respectively.
-
-``` nix
-      ++ foldl (prev: f: prev ++ f p) [] [
-        requires
-      ]))
-    # ...
-```
-
-This piece of code was the most challenging, to be honest.
-
-- `++` is the concatenation of the lists, so what follows `++` needs
-  also be a list.
-
-- `foldl` is a higher-order function that takes three arguments, here
-  `foldl () [] []`.
-
-- The ending `))` are to close function `(p: ...)` and function
-  `(python3.withPackages ...)`.
-
-The first argument to `foldl` is a *function*, the second argument is
-the initial value of an *aggregator*, and the third argument is a
-*list*.
-
-Generally, `foldl` goes over each element of the *list*, applying the
-*function* to the *aggregator* and the *list*'s element, storing the
-result of the *function* application to the *aggregator*. When there is
-no element left in the *list*, `foldl` returns the *aggregator*.
-
-Our *function* is
-
-``` nix
-(prev: f: prev ++ f p)
-```
-
-the initial value of the *aggregator*, here called `prev`, is
-
-``` nix
-[]
-```
-
-and the *list* is
-
-``` nix
-[ requires ]
-```
-
-We have only the single element in the list (`f` in our *function*), so
-there is just a single step and therefore `foldl` returns
-
-``` nix
-[] ++ (requires p)
-```
-
-- Recall that `p` is the attribute set with Python packages passed by
-  the `python3.withPackages`.
-
-- `( )` are here due to the precedence -- functions can be list's
-  elements, too! However, we need the result of the function call.
-
-- Yes, our *list* contains functions we apply to the attribute set with
-  Python packages to generate the list of Python packages to be included
-  in the development shell.
-
-Hypothetically, we could have `requires-doc`, the result of partial
-application of the `pypi2nix` to the list of *documentation*
-dependencies, and our list could look like
-
-``` nix
-[ requires requires-doc ]
-```
-
-In such a case, the result of the `foldl` would be
-
-``` nix
-[] ++ (requires p) ++ (requires-doc p)
-```
-
----
-
-It's nice to find out how things work. Here is the refactored version:
-
-``` nix
-# Return a list of derivations
-# - wanted-pkgs is a list of strings of wanted Python package names
-# - available-pkgs is attribute set of all Python packages available in Nix
-pypi2nix = wanted-pkgs: available-pkgs: let
-  pypi-name-to-nix-name = {
-    # "pypi-name" = "nix-name";
-    "SQLAlchemy" = "sqlalchemy";
-  };
-  to-nix-name = pypi-name: let
-    pkg-name = head (match "([^ =<>;~]*).*" pypi-name);
-  in
-    pypi-name-to-nix-name.${pkg-name} or pkg-name;
-  nix-names = map to-nix-name wanted-pkgs;
-in
-  attrValues (getAttrs nix-names available-pkgs);
-
-requires = pypi2nix pyproject.project.dependencies;
-
-buildPythonPackage {
-  dependencies = requires pythonPackages;
-  # ...
-
-let
-  wanted-pkgs = wanted-list: wanted-fns: available-pkgs:
-    foldl
-    (wanted-pkgs: wanted-from: wanted-pkgs ++ wanted-from available-pkgs)
-    (attrValues (getAttrs wanted-list available-pkgs))
-    wanted-fns;
-in
-  devShells.default =
-    pkgs.mkShell
-    {
-      packages = with pkgs; [
-        ruff
-        (python3.withPackages
-          (wanted-pkgs
-            [ "build" "mypy" ]
-            [ requires ]))
-        # ...
-```
-
-Feel free to compare to the original code:
-
-``` nix
-pypi2nix = list: pypkgs:
-  attrValues (getAttrs (map (n: let
-      pyname = head (match "([^ =<>;~]*).*" n);
-      pymap = {
-        "SQLAlchemy" = "sqlalchemy";
-      };
-    in
-      pymap."${pyname}" or pyname)
-    list)
-    pypkgs);
-
-requires = pypi2nix pyproject.project.dependencies;
-
-buildPythonPackage {
-  dependencies = requires pythonPackages;
-  # ...
-
-devShells.default = pkgs.mkShell {
-  packages = with pkgs; [
-    ruff
-    (python3.withPackages (p:
-      [p.build p.mypy]
-      ++ foldl (prev: f: prev ++ f p) [] [
-        requires
-      ]))
-    # ...
-```




> 2025-03-04: Add another nicer nix code suggestion

diff --git a/post/you-can-write-nicer-nix-code.md b/post/you-can-write-nicer-nix-code.md
index 58d3f93..136924a 100644
--- a/post/you-can-write-nicer-nix-code.md
+++ b/post/you-can-write-nicer-nix-code.md
@@ -19,6 +19,10 @@ Here are some suggestions:
 
 - Only use anonymous function when it fits a single line.
 
+- Either fit a function call with all the arguments at a single line, or
+  put each argument at new line with the same indent as called function.
+
+
 We use Nix at work and so I need to understand it. When I am trying to
 find out what happens in our `flake.nix`, I do refactor the code. Some
 of the source code of a template we use [is published][2] so I believe
@@ -348,14 +352,16 @@ let
     (attrValues (getAttrs wanted-list available-pkgs))
     wanted-fns;
 in
-  devShells.default = pkgs.mkShell {
-    packages = with pkgs; [
-      ruff
-      (python3.withPackages
-        (wanted-pkgs
-          [ "build" "mypy" ]
-          [ requires ]))
-      # ...
+  devShells.default =
+    pkgs.mkShell
+    {
+      packages = with pkgs; [
+        ruff
+        (python3.withPackages
+          (wanted-pkgs
+            [ "build" "mypy" ]
+            [ requires ]))
+        # ...
 ```
 
 Feel free to compare to the original code:




> 2025-03-03: Add nicer nix code suggestion

diff --git a/post/you-can-write-nicer-nix-code.md b/post/you-can-write-nicer-nix-code.md
index 18416cb..58d3f93 100644
--- a/post/you-can-write-nicer-nix-code.md
+++ b/post/you-can-write-nicer-nix-code.md
@@ -17,6 +17,8 @@ Here are some suggestions:
 
 - Let things in `let ... in ...` follow order.
 
+- Only use anonymous function when it fits a single line.
+
 We use Nix at work and so I need to understand it. When I am trying to
 find out what happens in our `flake.nix`, I do refactor the code. Some
 of the source code of a template we use [is published][2] so I believe
go back see post