
On Sun, Jul 31, 2016 at 09:17:09PM +0000, Ramnath R Iyer wrote:
Below is an updated version of working code. [...]
Well done! Now, to the questions:
1. If I wanted to write the logic encapsulated in `emit' directly within main, how would I do that? In my example, I was forced to extract it out as a separate method specifically to leverage pattern matching.
Pattern matching can be done via a `case` statement as well (and you provide an example of this just a few lines above the `emit` call). Personally, I much a prefer separate function as it is clearer (if you don't want to clutter top level use a `where` statement).
2. You mentioned outputStrLn has a type `String -> InputT IO ()'. How do you logically come to this conclusion? Is it because outputStrLn was taking a single String argument and had to return the same type returned by loop declared previously?
Correct, if we ask ghci about `ouputStrLn` it will reply: λ> :t outputStrLn outputStrLn :: Control.Monad.IO.Class.MonadIO m => String -> InputT m () but in this case you have written the signature to `loop` (it's always a good habit), so it's clear our function can only have this concrete data type.
3. Are there better/simpler/more idiomatic ways of structuring my program?
Yes there are: your program checks/pattern matches at every step and for each of those you have a case/if; it could get pretty messy if you were to add a few more actions. There is a nice way to handle these kind of situations, it involves monadic code. But before using monads you need to digest them! So keep following your course (if you are not following any, I like these two, which are gratis [1] [2]) and come back to this .hs after you tamed the mighty monad to refactor it! [1] http://learnyouahaskell.com/ [2] https://www.seas.upenn.edu/~cis194/spring13/lectures.html