Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: compose and pipe functions #38422

Closed
wants to merge 3 commits into from
Closed

lib: compose and pipe functions #38422

wants to merge 3 commits into from

Conversation

kimburgess
Copy link
Member

Provide base functions for function composition.

Motivation for this change

Just a couple of low level primitives that are likely useful across various modules / packages.

Rather than implementing these everywhere they're needed, it probably makes sense to include them here. I had a quick grep through the repo and could only find a single current implementation, which I've redirected back to this.

Things done
  • Tested using sandboxicomposeng (nix.useSandbox on NixOS, or option build-use-sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Fits CONTRIBUTING.md.

@@ -3,7 +3,7 @@
let
inherit (args) stdenv makeWrapper;
inherit (stdenv) lib isDarwin;
inherit (lib) overrideDerivation;
inherit (lib) overrideDerivation compose;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this method used here?

Copy link
Member Author

@kimburgess kimburgess Apr 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... you're right - it doesn't looks like that expression was actually in use there. I'll drop the inherit.

@edolstra
Copy link
Member

edolstra commented Apr 4, 2018

Not really in favor of this. Expressions like builtins.foldl' (flip compose) id are likely to be very slow. Also, the use of such abstractions can make code less readable. For instance, if I see f (g x) I know what it does, but if I see compose f g I have to look up the definition of compose first.

@kimburgess
Copy link
Member Author

kimburgess commented Apr 4, 2018

I'm still super green to Nix, so apologies for any lack of knowledge when it comes to perf characteristics - is there a reason for that suggested slowness in the implementation of pipe? From what I can see in the docs / implementation foldl' should be strict on the operator so evaluation should be the same as if everything was inlined + the overhead of flipping.

As for readability, I prefer pointfree (which these enable). The lack of an infix (.) operator for the straight compose function isn't ideal, but consider the following:

pipe [ a b c d ]

vs

x: d (c (b (a x)))

It comes down to stylistic preferences. Happy to keep it in my personal libs if it doesn't mesh with the style used through the rest of the repo.

@FRidh FRidh changed the title Composition lib: compose and pipe functions Apr 4, 2018
@telent
Copy link
Contributor

telent commented Apr 5, 2018

Entirely coincidentally I spent an hour or so yesterday looking for a compose function. I'm not sure I'd guess the definition of pipe correctly, but I'd have thought function composition is up there with map or fold/reduce in terms of widespread functional idiom

@dtzWill
Copy link
Member

dtzWill commented Apr 23, 2018

I have a definition of this too, with comment saying along the lines of "surely it exists already and but I'm blind so here we go"... Haha.

Are these named similarly elsewhere? Consistently? If so helps a bit with reading.
I mean pipe seems pretty clear :).

If perf is bad maybe it should just be a builtin! :P

@kimburgess
Copy link
Member Author

compose should be fairly familiar for people from most language backgrounds.

pipe is also common terminology across F#, OCaml, Elixir, Elm, Julia, Hack, LiveScript, the tc39 proposal and quite a few libraries for various languages, as well as UNIX pipes, although in most of these it's represented as the |> operator.

Happy to split these out if they're easier to consider in isolation.

Definitely agree that builtins would be optimal. If going that route, extending to . and |> operators would be beautiful, but I'm lazy and implementation here was trivial :)

@mmahut
Copy link
Member

mmahut commented Aug 3, 2019

What is the status of this pull request?

@kimburgess
Copy link
Member Author

@edolstra expressed some valid performance concerns with pipe, which are likely reason enough to drop that from inclusion in this PR.

I've just had a grep through the current repo state and could find another implementation of compose introduced here. Unfortunately github code search is a little rudimentary, but from a brief look across other nix projects the occasional implementation pops up elsewhere too. With this I'd still argue that there could be some value in just having it as part of base lib.

Let me know which way you'd like to go and I can either drop this down to just compose, or close this off without the merge.

@turboMaCk
Copy link
Member

In my opinion neither of this is useful unless it's defined as a infix or used in laguage where it's possible to write binary functions as infix (like haskells ``` syntax).

@Mic92
Copy link
Member

Mic92 commented Sep 22, 2019

Let's close this for now.

@Mic92 Mic92 closed this Sep 22, 2019
@Mic92 Mic92 mentioned this pull request Oct 19, 2019
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants