Maybe because I haven’t used languages like these in the past, but I hardly think this is elegant, much read readale. I would hate my life trying to parse code like this in a 10k LOC codebase.
It's actually very readable once you get the hang of it. The transition from imperative paradigms to Haskell can be tough, but once you've overcome this barrier, the code reads effortlessly. In your example case: split the string into a list of words, that is tokenize based on spaces. Then map the read function onto this, which will parse each of the "words" in the list into some type. Annotations would likely be needed here. Then sum this list.
I much prefer this over 10 levels of class indirections or procedural style.
Isn't it the case that anything is very readable once you get the hang of it?
I think the problem is exactly in the "get the hang of it" part. For some languages, that's really difficult, while for others it's almost trivial. From my own experience, Haskell is very very difficult to "get the hang of" despite my multiple attempts, while something like Javascript is trivial for me (interestingly enough, except when it uses too much of the new FP patterns!) even when I do not program on it daily.
> In your example case: split the string into a list of words, that is tokenize based on spaces.
You've made a common mistake. You're wiring your listener's thinking with the imperative inside-out approach that you're used to. Instead, it should be explained as this: "strSum = sum . map read . words" is "a sum of all parsed values of the original input of space-separated words". The reason you should avoid inside-out explanations is because in Haskell you're allowed to move from general ideas to specifics, and you can sprinkle `undefined` and `_` for specific details whilst thinking about general ideas and interfaces.
I really like the FP paradigm, but could you all stop using weird abbreviations and random characters as substitute for operations?
You don't do programming with chalk on a wallboard, for crying out loud. Ideally, you are using a good IDE with syntax completion. Therefore, readability matters more than the ability to bang out commands in as few keystrokes as possible.
If you're familiar with Haskell, this is something you can just look at and parse without thinking. It's all basic Haskell syntax and concepts (function composition and partial application). I haven't touched Haskell for a few years and I didn't have any trouble interpreting it as "strSum is a function that takes a single string argument, splits it by whitespace, interprets each chunk as a number, and returns the sum".
> Maybe because I haven’t used languages like these in the past [...]
Yes, that definitely the case.
If you know what each function above does, including the function composition dot (.), then this is like reading English — assuming you know how to read English.
In our codebase we enforced usage of `>>>` instead, which composes forward instead of backwards:
strSum = words >>> map read >>> sum
For most people this then becomes "Apply `words` to the input argument, pass the result to `map read` and then `sum` the results of that".
I don't think `.` is super complex to read and parse, but we had people new to Haskell so I thought it prudent to start them off just with `>>>` and keep it that way. Most things are read left-to-right and top-to-bottom in a codebase otherwise so I don't see why not.
Edit:
I also told everyone it's fine to just spell out your arguments:
stringSum sentence =
sentence
& words
& map read
& sum
In the example above `&` is just your average pipe-operator. Not currying when you don't have to is also fine, and will actually improve performance in certain scenarios.
Edit 2:
The truth is that there are way more important things to talk about in a production code base than currying, and people not using currying very much wouldn't be an issue; but they'll have to understand different pointer/reference types, the `ReaderT` monad (transformer), etc., and how a `ReaderT env IO` stack works and why it's going to be better than whatever nonsense theoretical stack with many layers and transformers that can be thought up. Once you've taught them `ReaderT env IO` and pointer types (maybe including `TVar`s) you're up and running and can write pretty sophisticated multi-threaded, safe production code.
In a production application you generally don't write code like that. I find it tends to be the opposite problem where you often see giant `do` blocks performing all sorts of monadic effects.
Yes but the notation of dot, plus such function names plus optional parens makes it sure read like English. That’s great but it’ll be a nightmare when you are also dealing with strings which similar English in it.
fleshmonad|1 year ago
I much prefer this over 10 levels of class indirections or procedural style.
brabel|1 year ago
instig007|1 year ago
You've made a common mistake. You're wiring your listener's thinking with the imperative inside-out approach that you're used to. Instead, it should be explained as this: "strSum = sum . map read . words" is "a sum of all parsed values of the original input of space-separated words". The reason you should avoid inside-out explanations is because in Haskell you're allowed to move from general ideas to specifics, and you can sprinkle `undefined` and `_` for specific details whilst thinking about general ideas and interfaces.
HdS84|1 year ago
You don't do programming with chalk on a wallboard, for crying out loud. Ideally, you are using a good IDE with syntax completion. Therefore, readability matters more than the ability to bang out commands in as few keystrokes as possible.
djur|1 year ago
devjab|1 year ago
Symmetry|1 year ago
runeks|1 year ago
Yes, that definitely the case.
If you know what each function above does, including the function composition dot (.), then this is like reading English — assuming you know how to read English.
bhargav|1 year ago
There are other languages which are functional as well. like the one in the article and like Elixir where readability is it sacrificed.
I still think readability is atrocious in this language. Sure I can get used to it, but I’d never want to subject myself to that
59nadir|1 year ago
I don't think `.` is super complex to read and parse, but we had people new to Haskell so I thought it prudent to start them off just with `>>>` and keep it that way. Most things are read left-to-right and top-to-bottom in a codebase otherwise so I don't see why not.
Edit:
I also told everyone it's fine to just spell out your arguments:
In the example above `&` is just your average pipe-operator. Not currying when you don't have to is also fine, and will actually improve performance in certain scenarios.Edit 2:
The truth is that there are way more important things to talk about in a production code base than currying, and people not using currying very much wouldn't be an issue; but they'll have to understand different pointer/reference types, the `ReaderT` monad (transformer), etc., and how a `ReaderT env IO` stack works and why it's going to be better than whatever nonsense theoretical stack with many layers and transformers that can be thought up. Once you've taught them `ReaderT env IO` and pointer types (maybe including `TVar`s) you're up and running and can write pretty sophisticated multi-threaded, safe production code.
solomonb|1 year ago
djur|1 year ago
elbear|1 year ago
epgui|1 year ago
worksonmymach|1 year ago
2. Reverse
Now you have:
words | map read | sum
Or..
$ cat words | map -e read | sum
bhargav|1 year ago
kreyenborgi|1 year ago
tromp|1 year ago