    module System.Information.Memory (
      MemoryInfo(..),
      parseMeminfo
      ) where

    toMB :: String -> Double
    toMB size = (read size :: Double) / 1024

    data MemoryInfo = MemoryInfo { memoryTotal :: Double
                                 , memoryFree :: Double
                                 , memoryBuffer :: Double
                                 , memoryCache :: Double
                                 , memoryRest :: Double      -- free + buffer + cache
                                 , memoryUsed :: Double      -- total - rest
                                 , memoryUsedRatio :: Double -- used / total
                                 }

    emptyMemoryInfo :: MemoryInfo
    emptyMemoryInfo = MemoryInfo 0 0 0 0 0 0 0

    parseLines :: [String] -> MemoryInfo -> MemoryInfo
    parseLines (line:rest) memInfo = parseLines rest newMemInfo
      where (label:size:_) = words line
            newMemInfo = case label of
                           "MemTotal:" -> memInfo { memoryTotal = toMB size }
                           "MemFree:"  -> memInfo { memoryFree = toMB size }
                           "Buffers:"  -> memInfo { memoryBuffer = toMB size }
                           "Cached:"   -> memInfo { memoryCache = toMB size }
                           _           -> memInfo
    parseLines _ memInfo = memInfo

    parseMeminfo :: IO MemoryInfo
    parseMeminfo = do
      s <- readFile "/proc/meminfo"
      let m = parseLines (lines s) emptyMemoryInfo
          rest = memoryFree m + memoryBuffer m + memoryCache m
          used = memoryTotal m - rest
          usedRatio = used / memoryTotal m
      return m { memoryRest = rest
               , memoryUsed = used
               , memoryUsedRatio = usedRatio
               }