because it is nicely consistent, especially for deletion and insertion.
But I've never seen any code do it like this. I guess there's a small semantic difference, but I haven't encountered a problem with it.
Why is this not popular?
I was looking at ormolu and its github issues today and wondered about a few things – especially since they apparently use a principled approach that differs from common formatting a bit
I also always write them like that unless forced to otherwise (for example, when declaring constraints for instances or type classes). My excuse is because the first real application I built was Purescript, rather than Haskell.
when you have non-vanilla function kinds (e.g. linear) the arrow's "kindness" almost always refers to what's on the left, meaning that if you write them leading you have to look on the previous row, instead of immediately behind the arrow. So everything is trailing, for consistency with the arrows
you don't have to align ., which is only one symbol, with the other things which are two
I find it really hard to read code like that. I also don't like how it looks like, which turns out to be a big deterrent to me trying it out for a while. :upside_down:
so copying, deleting and inserting lines into signatures are not high-priority edit actions for you?
I also find it pretty confusing that the visual indicator for the semantics of an identifier is in the following line.
can you describe why that is?
I would also find it nicer if the operator identifying the semantic role of the signature component were at the beginning of the line, but since your presented style creates ambiguities because e.g. constraints can be prefixed by any of ::, . or =>, the cognitive overhead seems obvious to me.
I think it's mostly habit. I usually use explicit forall even when they're not needed (a habit I got from Purescript), so I only have constraints after . or =>. I've gotten used to scanning type declarations and noticing where the => turns to ->. The problem with using them at the end of the line is alignment: my eyes need to zig-zag to parse. I find that to be a bigger hassle than having developed the heuristic of finding the "last =>".
The => and -> are not aligned, so it's harder to scan the function constraints vs inputs easily. At least, it is for me. The advantage here is, the end of the line tells you what kind of thing it is, constraint vs input. This is what I meant by 'zig-zagging', eyes go from left to right searching for those arrows, since they are not vertically aligned.
This vertically aligns the arrows, which makes them really easy to vertically scan, but then there's some footnotes, such as a constraint may start with :: or =>, and an input may start with => or -> (but only if it's the first input, subsequent inputs must start with ->. Then also, the output starts with ->, but it's the last one.
What I meant is, my brain is now used to these weird rules and I can easily scan type declarations. But if I moved the arrows at the end, I'd have to develop new heuristics. Additionally, I think that (for me at least), it's easier to follow vertically aligned code even with the caveats/special rules described above than to the zig-zag I mentioned.
If it's trailing the rule is that "the symbol to the right tells you what's on the left" so => on the right says the thing on the left is the constraint, -> tells you it's a parameter, and nothing tells you it's the final return type. Which I think is pretty cool
@Vladimir Ciobanu wonder if that is a neuological property. for me, it is hard in general to read repetitions. it's virtually impossible for me to count the characters in 000000000000 (maybe it's my astigmatism). so when I look at the aligned variant, I have a bit of a hard time keeping the focus on the right row, especially since the arrows are visually similar.
for the trailing variant, I assume that saliency is the main feature. the arrows have distinct shapes compared to the rest of a row, so I think I'm getting an instant map of the signature without parsing. maybe that's something my brain is overcompensating with, for the bad repetition parsing capabilities.
I always format constraints like this:
because it is nicely consistent, especially for deletion and insertion.
But I've never seen any code do it like this. I guess there's a small semantic difference, but I haven't encountered a problem with it.
Why is this not popular?
I guess simply because we have tuples for this purpose - but they're not strictly needed for passing dictionaries to functions, that's true
PureScript does that
does what? use this style? require tuples?
Curried style
cool
I used it occasionally. I like it because it makes it easy to add and delete Show instances when debugging
@Fintan Halpenny right, so what keeps you from using it exclusively? what's your downside?
I don't write Haskell professionally which is my greatest downside
But sticking with how people are used to seeing it is my only excuse. Otherwise it totally makes sense
ah ok :big_smile: I wonder how many people have a similar experience
I was looking at
ormolu
and its github issues today and wondered about a few things – especially since they apparently use a principled approach that differs from common formatting a bitmaybe I should get involved :expressionless:
I also always write them like that unless forced to otherwise (for example, when declaring constraints for instances or type classes). My excuse is because the first real application I built was Purescript, rather than Haskell.
awesome! I'm not alone after all
another question, @Fintan Halpenny and @Vladimir Ciobanu :
when you use curried style, do you place the
=>
at the beginning or end of the line?Not one of them, but in PS I put everything at the beginning, including
=>
I place them at the beginning. I usually format as
I prefer trailing because
.
, which is only one symbol, with the other things which are twoif you use VDQ it's also annoying, because you need to know if the thing on the left of the
->
is aforall
to tell if it's a VDQ or notI find it really hard to read code like that. I also don't like how it looks like, which turns out to be a big deterrent to me trying it out for a while. :upside_down:
so copying, deleting and inserting lines into signatures are not high-priority edit actions for you?
I also find it pretty confusing that the visual indicator for the semantics of an identifier is in the following line.
I would do before, but I'm seeing the benefits of trailing after writing Rust :sweat_smile:
how does it look in Rust?
Well the Rust formatter tends to add trailing commas is what I meant
that's something I desperately want for haskell as well :sad:
The trait bounds are usually done by having a where clause that lists the generic parameters with trailing commas
But you do stuff like
T: Clone + Debug
for a single parameterVladimir Ciobanu said:
can you describe why that is?
I would also find it nicer if the operator identifying the semantic role of the signature component were at the beginning of the line, but since your presented style creates ambiguities because e.g. constraints can be prefixed by any of
::
,.
or=>
, the cognitive overhead seems obvious to me.I think it's mostly habit. I usually use explicit
forall
even when they're not needed (a habit I got from Purescript), so I only have constraints after.
or=>
. I've gotten used to scanning type declarations and noticing where the=>
turns to->
. The problem with using them at the end of the line is alignment: my eyes need to zig-zag to parse. I find that to be a bigger hassle than having developed the heuristic of finding the "last=>
".what do you mean by "zig-zag to parse"?
The
=>
and->
are not aligned, so it's harder to scan the function constraints vs inputs easily. At least, it is for me. The advantage here is, the end of the line tells you what kind of thing it is, constraint vs input. This is what I meant by 'zig-zagging', eyes go from left to right searching for those arrows, since they are not vertically aligned.This vertically aligns the arrows, which makes them really easy to vertically scan, but then there's some footnotes, such as a constraint may start with
::
or=>
, and an input may start with=>
or->
(but only if it's the first input, subsequent inputs must start with->
. Then also, the output starts with->
, but it's the last one.What I meant is, my brain is now used to these weird rules and I can easily scan type declarations. But if I moved the arrows at the end, I'd have to develop new heuristics. Additionally, I think that (for me at least), it's easier to follow vertically aligned code even with the caveats/special rules described above than to the zig-zag I mentioned.
If it's trailing the rule is that "the symbol to the right tells you what's on the left" so => on the right says the thing on the left is the constraint, -> tells you it's a parameter, and nothing tells you it's the final return type. Which I think is pretty cool
And _seems_ to be unambiguous
It's a mix and match for the prefixing version
@Vladimir Ciobanu wonder if that is a neuological property. for me, it is hard in general to read repetitions. it's virtually impossible for me to count the characters in
000000000000
(maybe it's my astigmatism). so when I look at the aligned variant, I have a bit of a hard time keeping the focus on the right row, especially since the arrows are visually similar.for the trailing variant, I assume that saliency is the main feature. the arrows have distinct shapes compared to the rest of a row, so I think I'm getting an instant map of the signature without parsing. maybe that's something my brain is overcompensating with, for the bad repetition parsing capabilities.