I have just started trying to learn Haskell and tried to think of a practical, but simple problem to try and solve. I have a strong background in C, but am just beginning to dip my toes in the world of functional programming.
The idea came from my investing in notes on Prosper: given a list of note ratings, and a desired distribution, what should the next note purchase be, in order to most align with the desired distribution.
Here's an example:
Say I currently own 5 notes of an "A" rating, and 4 notes of a "B" rating. If my desired distribution is 50% "A" and 50% "B", then the next note purchased should be of a "B" rating. However, if my desired distribution was 90/10, the next note should be an "A" rating.
The below code seems to work (albeit with no error checking), but feels very unreadable. What are some ways I could refactor to make the code more readable or idiomatic to Haskell?
module Main where
import Data.List
import Data.Ord
main::IO()
main = print $ recommendNote [ "B", "C", "D", "D", "HR" ] [ 0, 0, 0, 0.5, 0.25, 0.25, 0]
noteTypes :: [String]
noteTypes = [ "AA", "A", "B", "C", "D", "E", "HR" ]
recommendNote :: (Ord a, Fractional a) => [String] -> [a] -> String
recommendNote notes targetDist = let y = zip (subtractLists targetDist (getDistribution notes)) noteTypes
in snd (maximumBy (comparing fst) y)
subtractLists :: (Num a) => [a] -> [a] -> [a]
subtractLists = zipWith (-)
count :: [String] -> String -> Int
count inList x = length $ filter (x==) inList
getNoteCount :: [String] -> [Int]
getNoteCount inList = map (count inList) noteTypes
getDistribution :: (Fractional a) => [String] -> [a]
getDistribution inList = percentize $ map fromIntegral (getNoteCount inList)
percentize :: (Fractional a) => [a] -> [a]
percentize inList = map (/ sum inList) inList