5 ms·
Python's `with` Function composition operators eg a |> b # Call `b` with `a` as an argument b <| a # Same as above, reversed direction Then you can d
by duped 4y ago
Python's `with`
Function composition operators eg
a |> b # Call `b` with `a` as an argument
b <| a # Same as above, reversed direction
Then you can do something like
let x : Map = collect <|
[a, b, c]
|> map(entries)
|> flatten
- whatshisface 4y agoI don't get it, how are |> and <| any different from parentheses?
- mikepurvis 4y agoChaining without nesting.
- whatshisface 4y agoIf you mean without closing parentheses, I think you can also do that in languages like Haskell with non-parenthetical function calls.
- mikepurvis 4y agoI'm not a Haskell user, but my experience with this in the Nix language is a bit mixed. It definitely works sometimes, but then you get a pileup of parenthesis nesting anyway, because the default is greedy and you have to control which functions get which arguments.
- nine_k 4y agoDon't $ signs work in Nix the way the work in Haskell? E.g. https://mmhaskell.com/blog/2021/7/5/function-application-using-the-dollar-sign- https://mmhaskell.com/blog/2021/7/5/function-application-usi...
- mikepurvis 4y agoIf so, I've never seen that style used or documented.
- pavon 4y agoIt also allows you to invert the order of the calls so they are written in the order they occur. Instead of paint(sand(cut(measure(wood)))), you can write wood | measure | cut | sand | paint, which is easier to read, especially if it splits over multiple lines or has additional arguments: paint(sand(cut(measure(wood, 12), 40, :WZ), 220), :red) wood | measure(12) | cut(40, :WZ) | sand(220) | paint(:red) IIRC you can do that in Haskell as well, but I forget the name of the feature. Many OOP libraries have started to adopt a chained method call style similar to this, but it is nice to be able to do with any function.
- wbadart 4y agoIn Haskell, if all the functions in the pipeline are pure, I'd probably write that as wood & measure 12 & cut 40 WZ & sand 220 & paint Red See https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-Function.html#v:-38- https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-...
- duped 4y agoCall/Pipe operators are just sugar for normal function calls. It's nice because adding or removing a call doesn't require balancing parentheses. It's helpful for writing stream or sequence/iterator based code and throwing debug utilities in the middle. It's less of an issue if your language has UFCS or other postfix function call syntax like mentioned in this thread, but if you don't this is nice to have.
- masklinn 4y ago> Python's `with` It's very common already: try-with-resource (java), using (C#), bracket (haskell), unwind-protect (common-lisp), ... though it the latter two it's more of a building block. Also building block: languages with a convenient and "unrestricted" syntax for anonymous function can just use that e.g. Smalltalk, Ruby, ... in Ruby a "with" is usually just passing a block to the corresponding object's constructor: # python with open(...) as f: ... # ruby File::open(...) do |f| ... end
- jbverschoor 4y agoI was under the impression that Elixir introduced this.
- masklinn 4y agoElixir has forward pipes, but didn't invent them. For instance Racket and Clojure have threading macros, which are more flexible as they're just macros (Clojure's `->` is equivalent to Elixir's pipe operator, but `->>` will fill in the last parameter rather than first, and `-->` lets you use a keyword to define where the parameter is inserted in each call). Haskell let anyone who wants define their own pipe operator, historically you had to BYO, which wasn't exactly hard: (|>) = flip ($) or x |> f = f x would do (modulo fixity), but today it's provided by default as "(&)".
- gpderetta 4y ago'with' is cool, but it is annoying that it creates a new scope. And then you have ExitStack if your lifetimes do not neatly map to scopes. And AsyncExitStack and async with if you happen to be in an async function. I prefer RAII.