(define (match:element variable restrictions)
(define (ok? datum)
(every
(lambda (restriction)
(restriction datum)
)
restrictions
)
)
(define (element-match data dictionary succeed)
(and
(ok? data)
(let ((vcell (match:lookup variable dictionary)))
(if vcell
(and
(equal? (match:value vcell) data)
(succeed dictionary)
)
(succeed (match:bind variable data dictionary))
)
)
)
)
element-match
)
It may not be densest or most compact indentation scheme, but damn is it readable for someone without a lisp/scheme background!Likewise, a lispier(?) and more compact compromise?:
(define (match:element variable restrictions)
(define (ok? datum)
(every
(lambda (restriction)
(restriction datum))
restrictions))
(define (element-match data dictionary succeed)
(and
(ok? data)
(let ((vcell (match:lookup variable dictionary)))
(if vcell
(and
(equal? (match:value vcell) data)
(succeed dictionary))
(succeed (match:bind variable data dictionary))))))
element-match)
Counting parens is silly when the editor can do it for you.
I'm highly resistant to novelty in this area, yet even I am using parinfer. A crappy implementation in Vim, at that, which only works in One direction: indent -> parens, and can get into an infinite loop fighting with Vim's undo.
Also I recently read on an HN thread I started: it was taken out of Calva due to bugs no one fixed.
About 90% of my problems arise when I shift the parens, e.g. going from `(+ (1 2))` to `(+ (+ 1 2) 3)` or the other way round - and if there is now ) or )) at the very end (but more likely at 4+, not 1 or 2.
How would any plugin know what I mean here? (I know + is a bad example as its commutative...).
Editing for lisp mirrors the language as a whole in that there's a learning curve, but once you've climbed it, it's a joy to work with. Because the syntax is so uniform, all you need is a handful of extensions/commands for full blown structural editing.
I get by splendidly in emacs with nothing but paredit and convenient keybindings(not a huge fan of paredit defaults).
But regardless, I think the answer you are looking for is:
Some of the coolest kids of all use rainbow delimiters so that they can easily identify the matching closing paren with their eyes!
One webserver framework, Axum, has the trait IntoResponse which is returned by something that implements Handler. A lot of things implement IntoResponse and/or Handler. In plain English you have handlers, these are parts of code that get selectively invoked for a request. The handlers return data that can be made into responses. It's powerful, but if something doesn't fit exactly, the Rust compiler throws gibberish errors at you. It's finnicky as hell.
But once you have written something that works, it is beautiful to read.
So it's difficult to write such code, and if it's easy for you then it's because you mastered the art.
The reading is not that bad as the indentation tells you where the brackets are and you don't really notice them.
This looks like how I've naively tried to format things, and having started with python kind of makes sense.
But trying to read / edit code with 5 parentheses bunched together, I have the hardest time telling if they are matched or where. Thank goodness for vim / helix auto-matching.
I just use the Tab key for indenting and it always work for me (there's a logic on where to break line to get correct indenting, and it makes it easy to see if you misplaced a parenthesis. Also, both Emacs and Vim, highlight the matched parenthesis, so I never wonder about if I have the correct number of closing parenthesis.
(foo
(bar
(baz (xyzzy arg))
(bar arg))
We know from the indentation that this is supposed to be a closed unit: (bar
(baz (xyzzy arg))
But it needs three closing parens ))) not just )).If this problem is not accidentally compensated by a ) in the wrong place elsewhere, this code will error out.
One simple thing you can do is just automatically reindent the whole block. The indentation will then match the incorrect parentheses and the problem will be clear. Undo the temporary reformatting and fix it.
This is exactly the point of my comment -- the absence of an obvious / reasonable automatic formatter is the problem I'm pointing to.
Honestly though, this style for ending parenthesis of block-type nodes makes a lot of sense to me. And you still retain the benefit of macro-ing your own syntax when you need it.
(
define (match:element variable restrictions)
(
define (ok? datum)
(
every
(
lambda (restriction)
(restriction datum)
)
restrictions
)
)
(
define (element-match data dictionary succeed)
(
and
(ok? data)
(
let ((vcell (match:lookup variable dictionary)))
(
if vcell
(
and
(equal? (match:value vcell) data)
(succeed dictionary)
)
(succeed (match:bind variable data dictionary))
)
)
)
)
element-match
)
Granted I'm not the one to optimize for since I don't use Lisp, but this just seems sane and easy to automate, and it looks like other non-Lisp languages.
Should we be doing this?:
void MyFunc() {
DoStuff();
DoOtherStuff();}
I'll happily tolerate some wasted space in that trade-off.
My "OTBS all the things" rules:
- Never horizontal align. Indentation is a simple tree, with each set of children indented 1 layer deeper, which can be 4 spaces or 1 tab.
ThisKindOfThing(
foo,
bar,
baz);
is generally dumb.- If a block is worth indenting for, the end of the block deserves its own line. Just do OTBS but also for parentheses if you've a long function call.
ThisKindOfThing (
foo,
bar,
baz
);
Is just more consistent and easier to manage while still being legible.- if you're ever splitting something across multiple lines there must be an indent.
myObj
.Foo()
.Bar()
.Baz();
- you're allowed to double-dip on tree depth - that is indent only one level for like 3 levels of tree, as long as the opening of that 3-deep jump is a clear one-liner and the end of it is a line that says ")))". Foo(Bar(Baz(
someVal
)));
- when splitting lines on infix operators, anything but commas go at the start of the line (also, bedmas counts as tree depth) foo
+ bar
+ baz
+ (
var1
* var2
* var3
)
+ quux;
(I hope?!)
It seems pretty clear that a threading macro which allows the user to place the "hole" being filled wherever they want is the answer.
Example: cl-arrows
(tree-transform-if predicate
transformer
(second tree)
depth)
> A problematic function indentation> Nineteen! Nineteen spaces of indentation! It's getting unruly.
Why, is there a shortage of whitespace these days??
> Such an indent, when used in deeply nested code, makes it too wide and unreadable.
Ah, I see! Well, I would argue the problem is not the indentation style. What makes your code unreadable is that it's too deply nested, and I would bet that no indentation style can help with that.
(claim Tuple3 (-> U U U U))
(define Tuple3 (lambda ( a b c )
(Pair a (Pair b c) )))
(claim tuple3Of (Pi ( (A U) (B U) (C U))
(-> A B C
(Tuple3 A B C ))))
(define tuple3Of (lambda ( A B C )
(lambda ( a b c )
(the (Tuple3 A B C )
(cons a (cons b c)) ))))
(claim Tuple5 (-> U U U U U U))
(define Tuple5 (lambda ( a b c d e )
(Pair a (Pair b (Pair c (Pair d e))))))
(claim tuple5Of (Pi ((A U) (B U) (C U) (D U) (E U))
(-> A B C D E
(Tuple5 A B C D E ))))
(define tuple5Of (lambda ( A B C D E )
(lambda ( a b c d e )
(the (Tuple5 A B C D E )
(cons a (cons b (cons c (cons d e))))))))
Diamond arrows exist, you know.
(-<> foo
bar
(baz)
(quux 1 2 3)
(fred 4 5 6 <>)
(frob 7 <> 8 <> 9))
All in all, this post reads like a rant, and I realized that upon reading "now what I'm about to suggest is likely not to your taste". That style of indentation is something I use often when writing calls to long-named functions like COMPUTE-APPLICABLE-METHODS and I haven't ever thought of it being not to my taste, or even of it being ugly as the author suggests.I'm aware of arrow-macros/diamond wands, and am using them myself. But I often have to write dependency-less libraries for moderately complicated algos, and that's where indentation style is the only thing I can rely on.
> (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.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
> 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.
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.
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)
Iterator methods are the only part of Rust/C# that feel like normal decent function composition. Except Haskell is backwards.
I predict that in another five years, he will write an article disparaging Lisp and purge it from his CV, and that will be that.
Yeah, someone working with ed its not going to like 19 repeated leading spaces across lines for vertical alignment. They will like that less than even somebody working with Notepad.
Who does that? LISP has a datastructured syntax, textformat has no meaning in it.
I think I once saw a project turning Scheme into a visual block-based representation, but I can't find it again.
* Not a bad language - well, maybe bad by today's standards, but undeniably a very important language - just goofy