
First of all, point-free declarations come naturally as you get more and more familiarized with Haskell. Don't push yourself to write every 'simple' function in point-free style. Regarding the types, remember that ghci is your friend :D Load your code as a module and ask ghci for the type of your functions (and their compositions). On Sun, 2011-06-05 at 19:46 +0100, Sean Charles wrote:
My confusion arises over: mapM_ putStrLn (traincodes legodata) Given that: mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
Here's how I read it: For any m that is a Monad, mapM_ takes a function that "takes an 'a' and returns it wrapped in a monad", a "list of a's" and returns a "monad containing 'unit'", the empty-list LISP-() undefined voidy thing.
There's another way to see it, which I found to be enlightening: mapM_ takes an "action" in the monad 'm', which needs an input of some type 'a' to run, and a list of appropriate input; it'll feed the input to the action repetitively, discarding the results. It's cousin mapM does the same, except it collects the results of running the action each time (preserving the original order in the input list).
Gluing it all together:
mapM_ :: Monad m => (a -> m b) -> [a] -> m () putStrLn :: String -> IO () trainCodes :: [Record] -> [String]
the type of my call then would seem to be:
String -> IO () -> [String] -> IO () "putStrLn" -> (trainCodes legodata) -> IO ()
No, it's not. The type is: (String -> IO ()) -> [String] -> IO () Notice the parenthesis, which remain as in the type of mapM_. This is due to the associative properties of the operator (->) (the type constructor): (a -> b) -> c /= a -> (b -> c) But a -> (b -> c) == a -> b -> c which is how types in Haskell are normally written: instead of: a -> (b -> (c -> d))), we write: a -> b -> c -> d the reverse (as pointed out above) is not valid.
So, am I finally beginning to get a grip on it all ?
I think so... :D