選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

80 行
3.1 KiB

  1. { ... }:
  2. rec {
  3. # Compute the fixed point of the given function `f`, which is usually an
  4. # attribute set that expects its final, non-recursive representation as an
  5. # argument:
  6. #
  7. # f = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }
  8. #
  9. # Nix evaluates this recursion until all references to `self` have been
  10. # resolved. At that point, the final result is returned and `f x = x` holds:
  11. #
  12. # nix-repl> fix f
  13. # { bar = "bar"; foo = "foo"; foobar = "foobar"; }
  14. #
  15. # Type: fix :: (a -> a) -> a
  16. #
  17. # See https://en.wikipedia.org/wiki/Fixed-point_combinator for further
  18. # details.
  19. fix = f: let x = f x; in x;
  20. # A variant of `fix` that records the original recursive attribute set in the
  21. # result. This is useful in combination with the `extends` function to
  22. # implement deep overriding. See pkgs/development/haskell-modules/default.nix
  23. # for a concrete example.
  24. fix' = f: let x = f x // { __unfix__ = f; }; in x;
  25. # Modify the contents of an explicitly recursive attribute set in a way that
  26. # honors `self`-references. This is accomplished with a function
  27. #
  28. # g = self: super: { foo = super.foo + " + "; }
  29. #
  30. # that has access to the unmodified input (`super`) as well as the final
  31. # non-recursive representation of the attribute set (`self`). `extends`
  32. # differs from the native `//` operator insofar as that it's applied *before*
  33. # references to `self` are resolved:
  34. #
  35. # nix-repl> fix (extends g f)
  36. # { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; }
  37. #
  38. # The name of the function is inspired by object-oriented inheritance, i.e.
  39. # think of it as an infix operator `g extends f` that mimics the syntax from
  40. # Java. It may seem counter-intuitive to have the "base class" as the second
  41. # argument, but it's nice this way if several uses of `extends` are cascaded.
  42. extends = f: rattrs: self: let super = rattrs self; in super // f self super;
  43. # Compose two extending functions of the type expected by 'extends'
  44. # into one where changes made in the first are available in the
  45. # 'super' of the second
  46. composeExtensions =
  47. f: g: self: super:
  48. let fApplied = f self super;
  49. super' = super // fApplied;
  50. in fApplied // g self super';
  51. # Create an overridable, recursive attribute set. For example:
  52. #
  53. # nix-repl> obj = makeExtensible (self: { })
  54. #
  55. # nix-repl> obj
  56. # { __unfix__ = «lambda»; extend = «lambda»; }
  57. #
  58. # nix-repl> obj = obj.extend (self: super: { foo = "foo"; })
  59. #
  60. # nix-repl> obj
  61. # { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; }
  62. #
  63. # nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; })
  64. #
  65. # nix-repl> obj
  66. # { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; }
  67. makeExtensible = makeExtensibleWithCustomName "extend";
  68. # Same as `makeExtensible` but the name of the extending attribute is
  69. # customized.
  70. makeExtensibleWithCustomName = extenderName: rattrs:
  71. fix' rattrs // {
  72. ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);
  73. };
  74. }