{ lib }: rec {
  mkNushellInline = expr: lib.setType "nushell-inline" { inherit expr; };

  toNushell = { indent ? "", multiline ? true, asBindings ? false }@args:
    v:
    let
      innerIndent = "${indent}    ";
      introSpace = if multiline then ''

        ${innerIndent}'' else
        " ";
      outroSpace = if multiline then ''

        ${indent}'' else
        " ";
      innerArgs = args // {
        indent = if asBindings then indent else innerIndent;
        asBindings = false;
      };
      concatItems = lib.concatStringsSep introSpace;
      isNushellInline = lib.isType "nushell-inline";

      generatedBindings = assert lib.assertMsg (badVarNames == [ ])
        "Bad Nushell variable names: ${
          lib.generators.toPretty { } badVarNames
        }";
        lib.concatStrings (lib.mapAttrsToList (key: value: ''
          ${indent}let ${key} = ${toNushell innerArgs value}
        '') v);

      isBadVarName = name:
        # Extracted from https://github.com/nushell/nushell/blob/ebc7b80c23f777f70c5053cca428226b3fe00d30/crates/nu-parser/src/parser.rs#L33
        # Variables with numeric or even empty names are allowed. The only requisite is not containing any of the following characters
        let invalidVariableCharacters = ".[({+-*^/=!<>&|";
        in lib.match "^[$]?[^${lib.escapeRegex invalidVariableCharacters}]+$"
        name == null;
      badVarNames = lib.filter isBadVarName (builtins.attrNames v);
    in if asBindings then
      generatedBindings
    else if v == null then
      "null"
    else if lib.isInt v || lib.isFloat v || lib.isString v || lib.isBool v then
      lib.strings.toJSON v
    else if lib.isList v then
      (if v == [ ] then
        "[]"
      else
        "[${introSpace}${
          concatItems (map (value: "${toNushell innerArgs value}") v)
        }${outroSpace}]")
    else if lib.isAttrs v then
      (if isNushellInline v then
        "(${v.expr})"
      else if v == { } then
        "{}"
      else if lib.isDerivation v then
        toString v
      else
        "{${introSpace}${
          concatItems (lib.mapAttrsToList (key: value:
            "${lib.strings.toJSON key}: ${toNushell innerArgs value}") v)
        }${outroSpace}}")
    else
      abort "nushell.toNushell: type ${lib.typeOf v} is unsupported";
}