OK, I'll bite ;-)
Let me just quote the example code from the provided link first:
Code:
tr -cs A-Za-z '\n' |
tr A-Z a-z |
sort |
uniq -c |
sort -rn |
sed ${1}q
"The code is self-explanatory if you are familiar with basic Unix command-line tools." -- made me LOL :D
Note, that we're talking about the beginners here, who probably think that console window is "that old MS-DOS system"...
Here's how you do it in five lines for the workhorse part, with the code that actually *is* self-explanatory (
especially if you're familiar with the basic constructs used; based on "Accelerated
C++") so, hey, I've stripped the comments, too:
Code:
string word;
map<string, int> counters;
while (cin >> word) ++counters[word];
for (auto word_count : counters)
cout << word_count->first << '\t' << word_count->second << '\n';
Note, that the "sort | ; uniq -c |; sort -rn |" part is *precisely* what I'd call "a typically clever, lengthy, low-level implementation" -- if you want to be closer to declarative (as opposed to imperative or "doing something low-level and complicated when unnecessary") programming you don't want to be thinking about all of this sorting and uniqueness and calling each of the respective functions to perform these operations manually, you much rather want to *declare* that this is what you want -- as in *declaring* that you're going to use an ordered map with unique keys (std::map).
Another piece of code from the link you've given:
Code:
import qualified System
import qualified Data.List as List
import qualified Data.Char as Char
import qualified Data.HashMap.Strict as HashMap
main :: IO ()
main = do
[arg] <- System.getArgs
text <- getContents
let n = read arg
putStr $ createReport n text
createReport :: Int -> String -> String
createReport n text =
unlines $
map (\(w, count) -> show count ++ " " ++ w) $
take n $
List.sortBy (\(w, count) (w', count') -> compare count' count) $
HashMap.toList $
HashMap.fromListWith (+) $
map (\w -> (w, 1)) $
words $
map Char.toLower $
map (\c -> if Char.isLetter c then c else '\n') $
text
Apparently, the author feels this is "a simple program in
Haskell that I feel is closest to McIlroy’s both in spirit and in letter."
Um... right, I guess I might as well add comments back:
Code:
#include <iostream>
#include <map>
#include <string>
int main()
{
using namespace std;
// store each word and an associated counter
string word;
map<string, int> counters;
// read the input, keeping track of each word and how often we see it
while (cin >> word) ++counters[word];
// write the words and associated counts
for (auto word_count : counters)
cout << word_count->first << '\t' << word_count->second << '\n';
}
Which one is most beginner-friendly? You be the judge...
And, hey, don't get me wrong, I actually like Haskell, think shell scripting proficiency is a must for the day to day productivity, and
Python makes a great first language.
This doesn't mean I have to agree with nonsensical argumentation used ;-)
While I actually
Python is a reasonable choice in general, for the more mathematically inclined (e.g., pure math, CS majors) I'd actually consider an FP language worth considering -- e.g., Scheme used to be used for many of the intro-to-programming university classes not that long ago (e.g., MIT 6.001 -- although, to be fair, I guess
Python might be taking over that role there, staying with the MIT example), it has basic/minimal syntax (some would say it has no syntax at all) which doesn't obstruct from learning the core concepts, there's an excellent book series (SICP, The Little Schemer, The Seasoned Schemer, The Reasoned Schemer). Nowadays, I'd also add Haskell or F# to the list.
Learning an FP PL first might be a good thing to start the programming journey with the right frame of mind. While both
Python and
C++ are multi-paradigm, I think we have to be honest and admit that most "newbies" will solely use the imperative aspects thereof, making the FP seem harder to grok further along the way. OTOH, it's not that hard to learn imperative programming once you've grokked FP.