Stream: nix

Topic: Mapping through list of attrSets to make a complex string


view this post on Zulip Andreas (Jun 14 2024 at 14:49):

Okay @Tim DeHerrera I might have the next newbie question here :smile: In any other language I write that would be no problem for me, but in Nix it is somewhat weird to me.

This is related to me finally doing the network config setting to have them permanently fixed. I have my list of attrsets:

  networkInterfaces = [
    { name = "enp4s0f0np0";
      metric = 200; }
    { name = "enp4s0f1np1";
      metric = 100; }
    { name = "enp6s0";
      metric = 300; }
    { name = "enp7s0";
      metric = 350; }
  ];

and I want to create this string

networking.dhcpcd.extraConfig = ''
  interface enp4s0f0np0
  metric 200

  interface enp4s0f1np1
  metric 100

  interface enp6s0
  metric 300

  interface enp7s0
  metric 350
'';

I think I got a bit lost in the plethora of string concatenation functions that are available ...

view this post on Zulip Srid (Jun 14 2024 at 14:50):

You want concatStringsSep. ChatGPT solution (untested):

{
  networkInterfaces = [
    { name = "enp4s0f0np0"; metric = 200; }
    { name = "enp4s0f1np1"; metric = 100; }
    { name = "enp6s0"; metric = 300; }
    { name = "enp7s0"; metric = 350; }
  ];

  networking.dhcpcd.extraConfig = let
    # Function to transform a single attribute set to a string
    formatInterface = interface: ''
      interface ${interface.name}
      metric ${toString interface.metric}
    '';
    # Transform each attribute set and join them with newlines
    formattedInterfaces = builtins.concatStringsSep "\n" (builtins.map formatInterface networkInterfaces);
  in ''
    ${formattedInterfaces}
  '';
}

view this post on Zulip Andreas (Jun 14 2024 at 14:51):

yeah that looks plausible, I'll test it :smile:

view this post on Zulip Tim DeHerrera (Jun 14 2024 at 14:51):

Yeah, might be able to do it more "manually" with a fold. Can sometimes end up being quite elegant depending on the situation

view this post on Zulip Andreas (Jun 14 2024 at 14:52):

you have an example?

view this post on Zulip Tim DeHerrera (Jun 14 2024 at 14:53):

On my phone arm, but I'll see if I can grab one

view this post on Zulip Andreas (Jun 14 2024 at 14:53):

because elegance might help here, I feel that a good old c-style for-loop is easier to read

view this post on Zulip Tim DeHerrera (Jun 14 2024 at 15:02):

sure but for loops don't exist in the purely functional realm :grinning:

Here is a basic fold:

let
  networkInterfaces = [
    {
      name = "enp4s0f0np0";
      metric = 200;
    }
    {
      name = "enp4s0f1np1";
      metric = 100;
    }
    {
      name = "enp6s0";
      metric = 300;
    }
    {
      name = "enp7s0";
      metric = 350;
    }
  ];
in
  builtins.foldl' (acc: x:
    ''
      interface ${x.name}
      metric ${toString x.metric}
    ''
    + acc)
  ""
  networkInterfaces

view this post on Zulip Tim DeHerrera (Jun 14 2024 at 15:02):

ends up being fairly similar to srids version

view this post on Zulip Andreas (Jun 14 2024 at 15:06):

okay so what does networkInterfaces in the very last line do?

But that looks a bit more concise

view this post on Zulip Tim DeHerrera (Jun 14 2024 at 15:08):

That is just the list of interfaces bound to a variable name. Are you generally familiar with how folds work? Essentially its a convenient mechanism in the purely functional style of accumulating values from a list into some other kind of data structure, in this case a string.

view this post on Zulip Tim DeHerrera (Jun 14 2024 at 15:09):

so foldl' takes 3 args, the first is a function to show how to append each value to the accumulation of values, the second is the starting data structure, in this case an empty string, and the final argument is the list to fold

view this post on Zulip Andreas (Jun 14 2024 at 15:11):

yeah now that starts making a bit more sense.

view this post on Zulip Andreas (Jun 14 2024 at 15:11):

I guess I am just not purely functional enough (yet)

view this post on Zulip Andreas (Jun 14 2024 at 15:12):

gonna try this later

view this post on Zulip Tim DeHerrera (Jun 14 2024 at 15:12):

Well understand maps and folds will get you pretty far on their own, so you are off to a good start

view this post on Zulip Andreas (Jun 14 2024 at 15:13):

yeah, I mean maps I am fairly familiar with in other languages. But for some reason I find Nix always a bit more obscure to use.

view this post on Zulip Andreas (Jun 15 2024 at 13:59):

Going back to my original problem, I figured I most likely have to go through networkmanager to set the metric value, using dhcpd won't do the trick.


Last updated: Nov 15 2024 at 12:33 UTC