Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??
Like I wrote in my earlier post, I almost always work top down. So, to take up your challenge, I will start with a top-level outline: read in the inputs, process them somehow, and then show the results. Since I don't know what it means (yet) to perform each of those tasks, I will use simple placeholders like id to represent each stage of the outline:
module Main where main = interact $ showOutput . process . readInput showOutput = id process = id readInput = id
This is legal Haskell that compiles and executes. It doesn't do much, however, merely echoing its input:
$ echo alpha beta | ghc -e main WordIndex.hs
alpha beta
Still, it shows how easy it is to start sketching a solution at a high level.

Next, working down, I will flesh out the outline. I won't worry about reading input from files or writing output to an index just yet. For now, I will focus on the core word-counting problem, adding logic to do just that:

module Main where import qualified Data.Map as Map main = interact $ showOutput . process . readInput showOutput = unlines . Map.foldWithKey show1 [] process = foldl accumulate Map.empty readInput = words show1 key count = (unwords [key, show count] :) accumulate hash key = Map.insertWith (+) key 1 hash
Notice that I did not need to alter the outline. All I did was add low-level detail to it. Now I have counts:
$ echo alpha beta | ghc -e main WordIndex.hs
alpha 1
beta 1

Continuing to refine the lower-level functionality, I will return to the I/O tasks. Like before, I will add lower-level functions, leaving the top-level outline largely unchanged:

module Main (main) where import Control.Monad import qualified Data.Map as Map import System.Environment main = control $ showOutput . process . readInput showOutput = unlines . Map.foldWithKey show1 [] process = foldl accumulate Map.empty readInput = words show1 key count = (unwords [key, show count] :) accumulate hash key = Map.insertWith (+) key 1 hash control f = readFiles >>= writeIndex . f readFiles = getArgs >>= liftM concat . mapM readFile writeIndex = writeFile "words.index"

Let me recap. I started with a top-level, executable outline and worked down from there. With two simple iterations I was able to add the counting functionality and then the I/O functionality. Now I have a complete solution that is largely equivalent to your code (ignoring details that don't matter for our top-down coding discussion).

As a demonstration, I will compile the code and use it to index itself:

$ ghc -O2 --make -o WordIndex WordIndex.hs
$ ./WordIndex *.hs
$ cat words.index
"words.index" 1
$ 1
(+) 1
(main) 1
(unwords 1
. 5
1 1
:) 1
= 9
>>= 2
Control.Monad 1
Data.Map 1
Main 1
Map 1
Map.empty 1
...

There you have it: top-down functional programming, or at least the way I do it in Haskell. I hope you will trust me that it was quick and easy. (It took much longer to write this explanation than the code.)

Cheers,
Tom


In reply to Here you go: an example of top-down FP by tmoertel
in thread TMTOWTDI... and most of them are wrong by tlm

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others taking refuge in the Monastery: (7)
    As of 2015-07-04 09:50 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









      Results (59 votes), past polls