pkgs: {
  toKDL = let
    lib = pkgs.lib;
    util = import ../. pkgs;

    inherit (lib)
      concatStringsSep
      mapAttrsToList
      any
      flip
      flatten
      filterAttrs
      optional
      const
      ;
    inherit (builtins) typeOf replaceStrings elem;
    inherit (util.str) concat;
    inherit (util.fn) compose;

    indentStrings = compose (concatStringsSep "\n") (map (concat "\t"));

    sanitizeString = replaceStrings ["\n" ''"''] ["\\n" ''\"''];

    literalValueToString = element: let type = typeOf element; in
      if type == "null"
      then "null"
      else if type == "bool"
      then
        if element
        then "true"
        else "false"
      else if type == "string"
      then ''"${sanitizeString element}"''
      else if elem type ["int" "float"]
      then toString element
      else abort "Not implemented type: ${type}";

    convertAttrsToKDL = name: attrs: let
      children =
        ((attrs._children or [])
        |> map (mapAttrsToList convertAttributeToKDL)
        |> flatten
        )
        ++
        (attrs
        |> filterAttrs (name: const <|
          !elem name [
            "_args"
            "_props"
            "_children"
          ]
        )
        |> mapAttrsToList convertAttributeToKDL);
    in
      concatStringsSep " " (
        [name]
        ++ map literalValueToString (attrs._args or [])
        ++ mapAttrsToList (name: value: "${name}=${literalValueToString value}") (attrs._props or {})
        ++ optional (children != []) ''
          {
          ${indentStrings children}
          }
        ''
      );

    convertListOfFlatAttrsToKDL = name: list: "${name} ${list |> map literalValueToString |> concatStringsSep " "}";

    convertListOfNonFlatAttrsToKDL = name: list: ''
      ${name} {
      ${indentStrings (map (convertAttributeToKDL "-") list)}
      }
    '';

    convertListToKDL = name: list:
      if !any (flip elem list) ["list" "set"]
      then convertListOfFlatAttrsToKDL name list
      else convertListOfNonFlatAttrsToKDL name list;

    convertAttributeToKDL = name: value: let
      vType = typeOf value;
    in
      if elem vType [
        "int"
        "float"
        "bool"
        "null"
        "string"
      ]
      then "${name} ${literalValueToString value}"
      else if vType == "set"
      then convertAttrsToKDL name value
      else if vType == "list"
      then convertListToKDL name value
      else abort ''
        Cannot convert type `(${typeOf value})` to KDL:
          ${name} = ${toString value}
      '';
  in compose (concatStringsSep "\n") (mapAttrsToList convertAttributeToKDL);
}