Readable Haskell

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
32 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Readable Haskell

Misja Alma
Hi,

I have been writing Haskell in my spare time for a couple of years now, but when I showed some code lately to a friend he remarked that he didn't find it very readable. Actually I agree, when I look at my own code of a couple of months old I have trouble figuring out too what exactly it is doing.

I'm coming from a Java and Scala background and there, especially for Java, are some generally accepted best practices that make sure that your teammates don't have too much trouble reading your code. E.g. write short functions with a single responsibility, use variable, class and function names that explain what they are meant for, etc.

I think some of those best practices, like short functions with single responsibility, are useful for Haskell as well. But Haskell is a different language than Java and has its own strong points and pitfalls regarding readability, so it probably needs different coding standards as well.

I have been looking on the Internet if I could find some tips about improving readability but all I could find was http://www.haskellforall.com/. Although there are some useful tips in there, this site seems to be aimed at making Haskell easier to read for newcomers from other languages. What I am interested in are tips from real projects that are built by real teams.
Does anybody have any tips, or are there some sites or books that I could read about this topic?

Thanks,
Misja


_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Branimir Maksimovic

Generally write functions with meaningfull names. Using symbols should be understandable and  clear.

Generally Haskell is easy to read.

Greets, Branimir.

On 9/19/20 5:02 PM, Misja Alma wrote:
Hi,

I have been writing Haskell in my spare time for a couple of years now, but when I showed some code lately to a friend he remarked that he didn't find it very readable. Actually I agree, when I look at my own code of a couple of months old I have trouble figuring out too what exactly it is doing.

I'm coming from a Java and Scala background and there, especially for Java, are some generally accepted best practices that make sure that your teammates don't have too much trouble reading your code. E.g. write short functions with a single responsibility, use variable, class and function names that explain what they are meant for, etc.

I think some of those best practices, like short functions with single responsibility, are useful for Haskell as well. But Haskell is a different language than Java and has its own strong points and pitfalls regarding readability, so it probably needs different coding standards as well.

I have been looking on the Internet if I could find some tips about improving readability but all I could find was http://www.haskellforall.com/. Although there are some useful tips in there, this site seems to be aimed at making Haskell easier to read for newcomers from other languages. What I am interested in are tips from real projects that are built by real teams.
Does anybody have any tips, or are there some sites or books that I could read about this topic?

Thanks,
Misja


_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Henning Thielemann
In reply to this post by Misja Alma

On Sat, 19 Sep 2020, Misja Alma wrote:

> Does anybody have any tips, or are there some sites or books that I
> could read about this topic?

It may be a bit old but we have some articles on style in the Haskell
Wiki:
   https://wiki.haskell.org/Category:Style
   https://wiki.haskell.org/Category:Idioms
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Tom Ellis-5
In reply to this post by Misja Alma
On Sat, Sep 19, 2020 at 05:02:41PM +0200, Misja Alma wrote:
> I have been writing Haskell in my spare time for a couple of years now, but
> when I showed some code lately to a friend he remarked that he didn't find
> it very readable. Actually I agree, when I look at my own code of a couple
> of months old I have trouble figuring out too what exactly it is doing.

Could you perhaps show the code?  Then I may be able to give
suggestions about how to improve it.

I have written a few articles about refactoring to improve readability
it Haskell, for
example:

* http://h2.jaguarpaw.co.uk/posts/good-design-and-type-safety-in-yahtzee/
* http://h2.jaguarpaw.co.uk/posts/refactoring-neural-network/

Tom
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Misja Alma
In reply to this post by Henning Thielemann
Thanks, these links are really useful! This definitely answers part of my question.

But what would still be really useful are some more or less generally accepted best practices about variable naming, indentation, when to use nested functions vs when to prefer keeping functions short, etc with regards to readability.

On Sat, 19 Sep 2020 at 17:10, Henning Thielemann <[hidden email]> wrote:

On Sat, 19 Sep 2020, Misja Alma wrote:

> Does anybody have any tips, or are there some sites or books that I
> could read about this topic?

It may be a bit old but we have some articles on style in the Haskell
Wiki:
   https://wiki.haskell.org/Category:Style
   https://wiki.haskell.org/Category:Idioms

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Oliver Charles-3
For indentation and very mechanical formatting, I suggest just using something like hindent, brittany or ormolu (all available at your local Hackage).

For naming, I follow Chris Done's suggestion: https://chrisdone.com/posts/german-naming-convention/

On Sat, 19 Sep 2020, at 4:32 PM, Misja Alma wrote:
Thanks, these links are really useful! This definitely answers part of my question.

But what would still be really useful are some more or less generally accepted best practices about variable naming, indentation, when to use nested functions vs when to prefer keeping functions short, etc with regards to readability.

On Sat, 19 Sep 2020 at 17:10, Henning Thielemann <[hidden email]> wrote:

On Sat, 19 Sep 2020, Misja Alma wrote:

> Does anybody have any tips, or are there some sites or books that I
> could read about this topic?

It may be a bit old but we have some articles on style in the Haskell
Wiki:
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
Only members subscribed via the mailman list are allowed to post.


_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Brody Berg
In reply to this post by Misja Alma
As a person who has been trying to learn Haskell for years I have a private joke related to reading Haskell source which is “It has been x days since I’ve seen completely unintelligible Haskell.” My sense is that language extensions are a big part of this - they can have a significant impact on readability and for a novice it is not at all clear how to differentiate the text changes wrought by the extension. And in the presence of multiple or even many extensions? Forget it. 

So yes, I agree Haskell can be hard to read - and we haven’t even dredged up the point/point-free debate!

With Kindness, 

Brody

On Sat, Sep 19, 2020 at 08:33 Misja Alma <[hidden email]> wrote:
Thanks, these links are really useful! This definitely answers part of my question.

But what would still be really useful are some more or less generally accepted best practices about variable naming, indentation, when to use nested functions vs when to prefer keeping functions short, etc with regards to readability.

On Sat, 19 Sep 2020 at 17:10, Henning Thielemann <[hidden email]> wrote:



On Sat, 19 Sep 2020, Misja Alma wrote:





> Does anybody have any tips, or are there some sites or books that I


> could read about this topic?





It may be a bit old but we have some articles on style in the Haskell


Wiki:


   https://wiki.haskell.org/Category:Style


   https://wiki.haskell.org/Category:Idioms




_______________________________________________

Haskell-Cafe mailing list

To (un)subscribe, modify options or view archives go to:

http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

Only members subscribed via the mailman list are allowed to post.

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Henning Thielemann
In reply to this post by Oliver Charles-3

On Sat, 19 Sep 2020, Oliver Charles wrote:

> For naming, I follow Chris Done's
> suggestion: https://chrisdone.com/posts/german-naming-convention/

Interesting perspective on German language. :-)

Btw. I would prefer ColumnExpression.update.

Or even ColExp.update because at the top of the module I would have
    import qualified ColumnExpression as ColExp
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Vanessa McHale-2
In reply to this post by Misja Alma

My 2¢: my style comes from writing silly code and revisiting it and realizing what to do differently.

I use stylish-haskell to order my import and I use hlint on my code.

I think compared to other languages, one writes more small functions. And I rely more on haddock + type signatures - I've learned some ways to avoid writing bad haddocks by getting frustrated by packages on Hackage.

Cheers,
Vanessa McHale

On 9/19/20 10:02 AM, Misja Alma wrote:
Hi,

I have been writing Haskell in my spare time for a couple of years now, but when I showed some code lately to a friend he remarked that he didn't find it very readable. Actually I agree, when I look at my own code of a couple of months old I have trouble figuring out too what exactly it is doing.

I'm coming from a Java and Scala background and there, especially for Java, are some generally accepted best practices that make sure that your teammates don't have too much trouble reading your code. E.g. write short functions with a single responsibility, use variable, class and function names that explain what they are meant for, etc.

I think some of those best practices, like short functions with single responsibility, are useful for Haskell as well. But Haskell is a different language than Java and has its own strong points and pitfalls regarding readability, so it probably needs different coding standards as well.

I have been looking on the Internet if I could find some tips about improving readability but all I could find was http://www.haskellforall.com/. Although there are some useful tips in there, this site seems to be aimed at making Haskell easier to read for newcomers from other languages. What I am interested in are tips from real projects that are built by real teams.
Does anybody have any tips, or are there some sites or books that I could read about this topic?

Thanks,
Misja


_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.

signature.asc (673 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Misja Alma
In reply to this post by Oliver Charles-3
>> For naming, I follow Chris Done's suggestion: https://chrisdone.com/posts/german-naming-convention/

Thanks! I didn't know it had this funny name, but the German name convention is also widely used in the Java world. 
But I wonder how well it works in Haskell, because unlike Java, in Haskell a lot of stuff can happen in a single line. With those long variable names, you'd have to 
break those lines several times. I haven't tried it yet, but I wonder how readable that is in Haskell?

Or am I looking at the wrong problem here, and should I first of all try to have as little happening in a single line of Haskell as possible?

On Sat, 19 Sep 2020 at 18:22, Oliver Charles <[hidden email]> wrote:
For indentation and very mechanical formatting, I suggest just using something like hindent, brittany or ormolu (all available at your local Hackage).

For naming, I follow Chris Done's suggestion: https://chrisdone.com/posts/german-naming-convention/

On Sat, 19 Sep 2020, at 4:32 PM, Misja Alma wrote:
Thanks, these links are really useful! This definitely answers part of my question.

But what would still be really useful are some more or less generally accepted best practices about variable naming, indentation, when to use nested functions vs when to prefer keeping functions short, etc with regards to readability.

On Sat, 19 Sep 2020 at 17:10, Henning Thielemann <[hidden email]> wrote:

On Sat, 19 Sep 2020, Misja Alma wrote:

> Does anybody have any tips, or are there some sites or books that I
> could read about this topic?

It may be a bit old but we have some articles on style in the Haskell
Wiki:
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
Only members subscribed via the mailman list are allowed to post.


_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Viktor Dukhovni
On Sat, Sep 19, 2020 at 07:07:38PM +0200, Misja Alma wrote:

> But I wonder how well it works in Haskell, because unlike Java, in Haskell
> a lot of stuff can happen in a single line.

One idiom for making "a lot of stuff in a single line" easier to read is
seen in:

    https://hackage.haskell.org/package/streaming-attoparsec-1.0.0.1/docs/Data-Attoparsec-ByteString-Streaming.html

    ...
    import Data.Function ((&))

    main :: IO ()
    main = Q.getContents           -- raw bytes
           & AS.parsed lineParser  -- stream of parsed `Maybe Int`s; blank lines are `Nothing`
           & void                  -- drop any unparsed nonsense at the end -- [1]
           & S.split Nothing       -- split on blank lines
           & S.maps S.concat       -- keep `Just x` values in the sub-streams (cp. catMaybes)
           & S.mapped S.sum        -- sum each substream
           & S.print               -- stream results to stdout

    lineParser = Just <$> A.scientific <* A.endOfLine <|> Nothing <$ A.endOfLine

Here, the function composition flows from left to right, in fact top
to bottom, rather than right to left (bottom to top over multiple
lines).  The key ingredient is the (&) operator which puts the
argument on the left and the function on the right.

I've also seen (the first borrowed from F#):

    (|>):   a -> (a -> b) -> b
    (|.>):  (a -> b) -> (b -> c) -> c
    (|$>)   f a -> (a -> b) -> f b
    (|*>)   f a -> f (a -> b) -> f b

And of course Conduit's (.|) is another instance of left-to-right
style for expressing long composition chains.

Returning to the streaming example, since in `streaming` transformations
of streams are performed via function application (no new operator like
Conduit's (.|)), the left-to-right style uses (&).

Of course even with the flow made clear, and names well chosen, one
still has to come to grips with some rather powerful, highly polymorphic
idioms, whose purpose in each context may warrant a comment in code that
is to be accessible to those still learning the ropes.  The somewhat
non-obvious "void" here is but a mild example.

--
    Viktor.

[1] One slightly non-obvious thing at first blush about streams is that
    "void" does not perturb the content of the stream, it only drops the
    stream's terminal value.  Streams are functors in that terminal value,
    so it turns out, surprisingly at first, that the two variants of
    "print the stream" below are identical.

        s :: Show a => Stream (Of a) IO r
        s = ...

        -- The relevant functor here is: F r = (Stream (Of a) IO) r
        -- thus, void s :: Stream (Of a) IO ()

        S.print . void $ s
        -- same as
        void . S.print $ s

    So, for a reader not steeped in the streaming library, one might even
    comment on the role of "void" in more detail:

           ...
           & AS.parsed lineParser  -- stream of parsed `Maybe Int`s; blank lines are `Nothing`
           & void                  -- Replace the stream `Return` value `r` with `()`
                                   -- discarding parser errors, see 'AS.parsed'.
           ...

    So that nobody is left wondering at stream processing continuing
    past "void", which in more mundate contexts one expects to not
    return anything useful to be further processed.

    This briefly caught me by surprise in the "all in one line"
    right-to-left example at the end of the document:

        S.print . void $ AS.parsed (A.scientific <* A.many' A.space) "12.3 4.56  78.9"

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Ben Franksen
In reply to this post by Oliver Charles-3
Am 19.09.20 um 18:22 schrieb Oliver Charles:
> For naming, I follow Chris Done's suggestion:
> https://chrisdone.com/posts/german-naming-convention/

FWIW, I tend to disagree with the position presented in this blog, at
least in the generality in which it is stated. Yes, long names can be
useful to enhance readability, but this is mostly the case when naming
highly specific things.

In Haskell, core algorithms often implement some algebraic theory. It is
not by accident that mathematical formulae, including applications in
the natural sciences, almost exclusively use single letters or very
short names. Understanding such formulae at a glance requires
familiarity with the notational conventions used, but once you have
achieved that familiarity, the short names actually /improve/
readability, assuming the naming convention is applied in a consistent
manner.

It is also no accident that formulae typically make up only a part of
the complete text. A complex formula needs to be accompanied by precise
definitions and explanations. Whenever you write code for which it is
not immediately obvious why it was done in exactly this way, add a
comment that explains what is going on!

To illustrate my point, here is some code that implements a highly
non-trivial algebra I wrote some time ago:

https://hub.darcs.net/darcs/darcs-screened/browse/src/Darcs/Patch/V3/Core.hs#176

I think using longer names in this code would be awkward and
distracting. Also note that the naming convention is documented:

https://hub.darcs.net/darcs/darcs-screened/browse/src/Darcs/Patch/V3/Core.hs#131

I even introduced operator symbols +| and -| as synonyms for some
Data.Set operations in order to make the formulae more concise (and
thus, IMHO, easier to read).

It goes without saying that you cannot read non-trivial code like this
as you read english prose. There is simply no way to understand it
without having at least a rough idea of the underlying theoretical
foundations.

Cheers
Ben

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Ignat Insarov
Ben, I think your proposition is righteous and uncontestable in
theory, and I stand by you. Unfortunately the practice hardly aligns
with the sermon.

No one writes Mathematics in monospace ASCII left to right. They go to
great lengths to actually type set things, generously use large and
small font, bold and cursive, write above and below the line, use
Greek and Hebrew and a myriad infix symbols. And for a reason —
compare a latex source of a _«notation heavy»_ paper with it rendered.

One may approach mathematical style in program source with generous
use of Unicode, but few dare. Even type setting code in proportional
font is considered heresy by many — just so that they may banish
proper tabulation and _indent with spaces_. So, even the proponents of
the mathematical style do not care to follow it as soon as it requires
a little effort. _(Hoω h∀rd may it be to g∃t some ∪nic⊕de on one's
kεyb∅arδ? See also the packages `base-unicode-symbols`[1] and
`containers-unicode-symbols`[2].)_ Therefore I think for many it is
merely an excuse for writing ugly code.

The Darcs code you show illustrates the point Chris Done speaks for as
well. Observe top level names: `displayPatch`, `commuteConflicting`,
`cleanMerge` — quite German! Then there is `ctxAddInvFL` and
`mapFL_FL`, but that from other modules. Finally, I tried to find out
what `Prim` stands for — I went as far as to the index of `darcs` on
Hackage[3] but no luck. And `prim` is the most frequent in the list of
words of the module, with 125 occurrences in normalized case.
Primitive? Primary? Prime? Primavera?

[1]: https://hackage.haskell.org/package/base-unicode-symbols
[2]: https://hackage.haskell.org/package/containers-unicode-symbols
[3]: https://hackage.haskell.org/package/darcs-2.16.2/docs/doc-index-P.html
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

migmit-2
True, but it might have something to do with the fact that mathematics was invented long before monospaced fonts. And hand-writing integrals, or quantifiers, or the empty-set symbol, is just as easy as writing digits.

I would rather agree with Ben: there are lots of places where long identifiers are distracting. Sometimes they make sense, but a lot of times they just don't.

> On 20 Sep 2020, at 14:02, Ignat Insarov <[hidden email]> wrote:
>
> Ben, I think your proposition is righteous and uncontestable in
> theory, and I stand by you. Unfortunately the practice hardly aligns
> with the sermon.
>
> No one writes Mathematics in monospace ASCII left to right. They go to
> great lengths to actually type set things, generously use large and
> small font, bold and cursive, write above and below the line, use
> Greek and Hebrew and a myriad infix symbols. And for a reason —
> compare a latex source of a _«notation heavy»_ paper with it rendered.
>
> One may approach mathematical style in program source with generous
> use of Unicode, but few dare. Even type setting code in proportional
> font is considered heresy by many — just so that they may banish
> proper tabulation and _indent with spaces_. So, even the proponents of
> the mathematical style do not care to follow it as soon as it requires
> a little effort. _(Hoω h∀rd may it be to g∃t some ∪nic⊕de on one's
> kεyb∅arδ? See also the packages `base-unicode-symbols`[1] and
> `containers-unicode-symbols`[2].)_ Therefore I think for many it is
> merely an excuse for writing ugly code.
>
> The Darcs code you show illustrates the point Chris Done speaks for as
> well. Observe top level names: `displayPatch`, `commuteConflicting`,
> `cleanMerge` — quite German! Then there is `ctxAddInvFL` and
> `mapFL_FL`, but that from other modules. Finally, I tried to find out
> what `Prim` stands for — I went as far as to the index of `darcs` on
> Hackage[3] but no luck. And `prim` is the most frequent in the list of
> words of the module, with 125 occurrences in normalized case.
> Primitive? Primary? Prime? Primavera?
>
> [1]: https://hackage.haskell.org/package/base-unicode-symbols
> [2]: https://hackage.haskell.org/package/containers-unicode-symbols
> [3]: https://hackage.haskell.org/package/darcs-2.16.2/docs/doc-index-P.html
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Sven Panne-2
Am So., 20. Sept. 2020 um 14:20 Uhr schrieb MigMit <[hidden email]>:
[...] there are lots of places where long identifiers are distracting. Sometimes they make sense, but a lot of times they just don't.

I think a good rule of thumb is: The length of an identifier should be proportional to the size of the scope in which it is valid.

As an example: If you design an API, names like "openBinaryFile", "handleValidationError", "primaryDrawingContext" are a good idea. If you have a simple 1-line or 2-line helper function, one-letter names can make things vastly more readable, because you can see the "meat" of the code more easily without drowning in 20-letter identifiers spilled over 5 lines. So just using "ctx" or even "c" for "primaryDrawingContext" in a one-liner can improve things. This is even more true when you have a type annotation with long, descriptive type names for this function.

But all of this is very subjective, and in the end writing good, readable code is a bit of an art. There are guidelines and tips on how to do this, but there can never be hard and fast rules which will make everybody happy.

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Taeer Bar-Yam
Can we agree that it's possible to go too far? Even in the global scope.
https://github.com/Quotation/LongestCocoa.

I think another factor that comes into play is how frequently you use the
function/value. If it comes up only once in a while, then every time someone
encounters it they are likely to have to remind themselves what all the
abreviations mean. If it comes up more frequently, then they likely already saw
it 10 lines ago, and remember. If it comes up very frequently, then whatever
name you assign it takes on its own meaning. Think about `map` or, in bash land
`ls` and `cd`. Unless you just started using bash, you're not going to think
"Oh. cd stands for 'change directory'". It's just… cd.

And at the same time, using a long name for something that's going to come up
every couple of lines is, IMO, distracting. Having all of the information be
within what your eye can easily take in at once has huge advantages. Not to
mention, can you imagine writing `changeDirectory` and `printDirectoryContents`
every time?

It's a balancing act. Obviously, the opposite extreme carries its own problems.

  --Taeer
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

MarLinn
In reply to this post by Viktor Dukhovni

    main :: IO ()
    main = Q.getContents           -- raw bytes
           & AS.parsed lineParser  -- stream of parsed `Maybe Int`s; blank lines are `Nothing`
           & void                  -- drop any unparsed nonsense at the end -- [1]
           & S.split Nothing       -- split on blank lines
           & S.maps S.concat       -- keep `Just x` values in the sub-streams (cp. catMaybes)
           & S.mapped S.sum        -- sum each substream
           & S.print               -- stream results to stdout

There's still quite a bit that can be improved here.

First of all: comments are good. But whenever you write a comment, ask yourself "could I choose a better name instead?" Make the code self-documenting at all usage sites by choosing a good name once. It's a good idea for every language, but this piece of code is a good example of how to apply it. So, first step:

	main ∷ IO ()
	main = Q.getContents
	     & parseLines
	     & dropUnparsed	-- Add the explanation/link definition side
	     & splitOnBlankLines
	     & catMaybes'	-- why write "it's catMaybes", when you could just write "catMaybes"?
	     & S.mapped S.sum
	     & S.print
Do you need more functions this way to store the names? Yes. Which is a good thing, because they might be reusable. Of course there's a limit; if every function fits in half a line, you've probably gone too far.

Second step: Thinking from left to right is a remainder from thinking imperatively. If you just turn around the top level of the code, the reader is forced to a game of ping pong while reading, so it can even make it harder to understand. So let's get rid of that (&) crowbar.

	main ∷ IO ()
	main = S.print
	     . S.mapped S.sum
	     . catMaybes'	-- by the way, there's probably a better name for what it's actually doing. "dropBlankLines", maybe?
	     . splitOnBlankLines
	     . dropUnparsed
	     . parseLines
	     $ Q.getContents

There's more reasons why going against Haskell's natural grain is a bad idea, and you provided the perfect hook to talk about it:

    (|>):   a -> (a -> b) -> b
    (|.>):  (a -> b) -> (b -> c) -> c
    (|$>)   f a -> (a -> b) -> f b
    (|*>)   f a -> f (a -> b) -> f b


Operators have the inherent problem that there aren't many symbols to choose from. That means that almost all operators are overloaded. For example, (|>) will be confused with the one from Data.Sequence. Yes, there's unicode. I love unicode (see that sneaky little "∷" up there?) so I've tried using Unicode in operators before, but one single person using the project had their device set to a C locale and so my whole library was search-and-replaced. It's still 1968 out there, so there's like 10 symbols to choose from.

And even if you could use more symbols, operators still have the inherent problem that they can't contain any letters. What exactly does (>>?$>) mean? Or (|>||>)? Or (<<*>@)?

So why not rely on the operators that are widely used instead of crowbaring new ones in just so that we can keep programming in C.



_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Ignat Insarov
In reply to this post by Taeer Bar-Yam
Command shell is a very old and peculiar human interface — if human at
all. They had 80 character wide screens and visibly lagging connexion.
We have retina screens, GPU accelerated rendering and magical
auto-completion. Imagine those commands were buttons that you could
press. Would you prefer a button to say _«`ls`»_ or _«list files»_,
_«`cd`»_ or _«change directory»_? For a vivid example, imagine a web
site where you have `lgn` and `plrq` instead of _«log in»_ and _«pull
request»_. Would you like that?

Getting back to Mathematics — this is where abstraction and notation
come in. We can give names to things and we can use scoping. But
neither mathematicians nor system administrators invent new
terminology for every next paper or script — maybe a few key words.
Industrial programming is yet another thing. I imagine when you have a
record with a hundred fields it pays off to have longish field labels.
And you cannot expect the next person to read your code from top to
bottom so that they get used to its peculiar vocabulary. For example,
today I am merging two branches of a 10 thousand lines code base that
diverged last Spring. Guessing the difference between `rslt` and `res`
is the last thing I need. You do not need to call your context
_«`ctx`»_ and your result _«`rslt`»_ — there are already words for it.

There was a time when every character needed to be typed and there was
a rectangle of only some 80×25 characters visible at once. Things have
changed. I can have two terminals of 119×61 characters each with a
fixed width font, and perhaps twice that with proportional. The number
of characters it takes to type an identifier in a smart code editor is
proportional to the logarithm of the number of identifiers in scope,
not to their length.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

Ian Zimmerman-2
On 2020-09-21 00:30, Ignat Insarov wrote:

> We have retina screens, GPU accelerated rendering and magical
> auto-completion.

Who's "we"? 1 and 2 are constrained by money. 1 and 3 are also
constrained by personal preference.

I need a _big_ screen because I also do photo processing beside coding,
and I can't afford 2 screens, one big and another high density.

And I use completion only by explicit request (ie. a specific
keybinding), because it isn't good enough (and can't be) to be always
right, and for me the stress from correcting it when wrong outweighs the
benefit of the common case, when right.

Veering off-topic, hence redirecting replies to myself.

--
Ian
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Readable Haskell

migmit-2
In reply to this post by Ignat Insarov
My guess is that most of Café members would agree that if given a choice between buttons with short labels and buttons with long labels they would ask to revert back to CLI. Maybe I'm wrong here, but I think Unix-style CLI is not going anywhere any time soon, regardless of retina screens and any other bells and whistles of modern GUIs. Don't get me wrong, GUIs are great for a lot of specific tasks, but CLI still outshines them in many areas, and I think short command names are a part of a reason for that.

Not just command names, in fact; in a one-liner I would rather write "while read a; do cp $a...; done" than "while read filename; do cp $filename...; done". They are exactly the same, but it's simply easier to deal with a short line — read it, edit it etc.

And, as Haskell makes it easier to use and control local variables, I think it's even more forgiving about short names. In C you'd need a descriptive name simply to make sure you don't use your loop counter somewhere inside the loop; but in Haskell, due to immutability, you don't usually have to worry.

> On 20 Sep 2020, at 21:30, Ignat Insarov <[hidden email]> wrote:
>
> Command shell is a very old and peculiar human interface — if human at
> all. They had 80 character wide screens and visibly lagging connexion.
> We have retina screens, GPU accelerated rendering and magical
> auto-completion. Imagine those commands were buttons that you could
> press. Would you prefer a button to say _«`ls`»_ or _«list files»_,
> _«`cd`»_ or _«change directory»_? For a vivid example, imagine a web
> site where you have `lgn` and `plrq` instead of _«log in»_ and _«pull
> request»_. Would you like that?
>
> Getting back to Mathematics — this is where abstraction and notation
> come in. We can give names to things and we can use scoping. But
> neither mathematicians nor system administrators invent new
> terminology for every next paper or script — maybe a few key words.
> Industrial programming is yet another thing. I imagine when you have a
> record with a hundred fields it pays off to have longish field labels.
> And you cannot expect the next person to read your code from top to
> bottom so that they get used to its peculiar vocabulary. For example,
> today I am merging two branches of a 10 thousand lines code base that
> diverged last Spring. Guessing the difference between `rslt` and `res`
> is the last thing I need. You do not need to call your context
> _«`ctx`»_ and your result _«`rslt`»_ — there are already words for it.
>
> There was a time when every character needed to be typed and there was
> a rectangle of only some 80×25 characters visible at once. Things have
> changed. I can have two terminals of 119×61 characters each with a
> fixed width font, and perhaps twice that with proportional. The number
> of characters it takes to type an identifier in a smart code editor is
> proportional to the logarithm of the number of identifiers in scope,
> not to their length.

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
12