5 ms·
> (tree-transform-if predicate > transformer > (second tree) > depth) > A problematic functio
by behnamoh 2y ago
> (tree-transform-if predicate
> transformer
> (second tree)
> depth)
> A problematic function indentation
> Nineteen! Nineteen spaces of indentation! It's getting unruly. Such an indent, when used in deeply nested code, makes it too wide and unreadable. If you add the strict one-per-line alignment of arguments, it's also painfully long line-wise.
I think this is more a problem with languages that encourage (or don't discourage) deeply nested function calls. I face the same issue in Python, although Python kinda discourages me to do:
foo(
bar(
baz(
far(
faz(...)))))
Instead, Python and Pythonic idioms encourage a "step by step" approach:
a = faz(...)
b = far(a)
...
I don't know which is "better"—the first approach requires thinking ahead about the chain of functions we're about to call while the second one is more like a gradual development of the solution, albeit being more verbose than the former.
- phoe-krk 2y agoYou can have the same step-by-step in Lisp via LET*. The problem outlined by the author happens when you have a function call where 1) the operator has a long name, 2) there are many arguments. The TREE-TRANSFORM-IF is such a case and you can't solve it by just "going step by step".
- behnamoh 2y agoYes, I think for whatever reason, Lisp languages tend to use long names for funcs and vars whereas Haskell and other FP languages prefer symbols like >>=, <$>, etc. Personally, I prefer somewhere in the middle. > The TREE-TRANSFORM-IF is such a case and you can't solve it by just "going step by step". Yes, this is a good point.
- skydhash 2y agoWhy not just locally bind it to something shorter with let? Lisp is flexible enough that this is a non issue.
- phoe-krk 2y agoYou introduce four new variables. You get five lines instead of four, and four of these lines are pure cognitive overhead.
- martin-t 2y agoI prefer a third approach - chaining method calls via `.method()`. C#'s LINQ extension methods and Rust's iterator methods do it and I find it to be the best of both worlds most of the time.
- behnamoh 2y agoSo the "fluent design" approach? I like that too, and many OO languages allow for that, but I haven't seen that approach in functional programming.
- 3836293648 2y agoReally? Iterator methods are the only part of Rust/C# that feel like normal decent function composition. Except Haskell is backwards.
- UltraSane 2y agoThe second Python method that uses intermediary variable is what I use because it works much better with a debugger I also like this trick to avoid nested for loops: import itertools names = ['Bob', 'Sam'] nums = [1,2] letters = ['A','B'] for name,num,letter in itertools.product(names,nums,letters): print(f"{name} {num} {letter}") Bob 1 A Bob 1 B Bob 2 A Bob 2 B Sam 1 A Sam 1 B Sam 2 A Sam 2 B
- Pxtl 2y agoThat deep nest of function calls is why I love languages that have bash-style pipelining as a built in feature, either with explicit shell piping features, or where everything Function(myObj) is also implicitly myObj.Method() Then it becomes (eg PowerShell, a language I hate but use constantly) Faz | Far | Baz | Bar | Foo Or (more C++/Java/C#-ish) Faz() .Far() .Baz() .Bar() .Foo() In this way the data and execution flows forwards instead of backwards and you don't have a pyramid of indentation. I don't know why we're so stuck on prefix notation for function calls. Postfix is just easier to read in long chains.
- sitkack 2y agoIn Python you have the wonderful https://github.com/pytoolz/toolz https://github.com/pytoolz/toolz from toolz import pipe pipe('hello',lambda w: ( "foo", w ), lambda y: [ 0, y, 1 ]) [0, ('foo', 'hello'), 1] You can used named functions, but they would need to be define above in upper scope def h(x): return ( "foo", x ) def g(x): return [ 0, x, 1] pipe('hello', h, g)
- behnamoh 2y agothanks, I'll check this out. I've seen similar libs before, like "pipes" which also does piping through the "|" symbol.
- aartaka 2y agoThis is a good style indeed, and I'm using it a lot in JavaScript, but you have to admit that it's never as consistent as that—there are basic functions mixed into it, and some lambdas, and whatever.