How to resolve the algorithm Rosetta Code/Rank languages by popularity step by step in the Haskell programming language
How to resolve the algorithm Rosetta Code/Rank languages by popularity step by step in the Haskell programming language
Table of Contents
Problem Statement
Sort the most popular computer programming languages based in number of members in Rosetta Code categories. Sample output on 02 August 2022 at 09:50 +02
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Rosetta Code/Rank languages by popularity step by step in the Haskell programming language
The Haskell code you provided is divided into two parts:
-
The first part defines the data types and functions to parse the JSON response from the MediaWiki API. The response contains a list of programming languages and their corresponding categories.
-
The second part uses the
Network.Browser
library to fetch the HTML response from the MediaWiki API and parses it to extract the programming languages and their popularity.
Here's a detailed explanation of each part:
First Part:
-
Data Types:
Language
data type represents a single programming language with its name and quantity (number of articles in the corresponding category).Report
data type represents the entire response to the query and contains a collection of languages and an optional continuation string.
-
JSON Parsing:
- The
instance FromJSON Language
andinstance FromJSON Report
instances define how to parse JSON objects intoLanguage
andReport
data types, respectively.
- The
-
Pretty Printing:
- The
showLanguage
function pretty-prints a single language. - The
showRanking
function pretty-prints languages with common rank. - The
showLanguages
function sorts and groups languages by rank and then pretty-prints them.
- The
-
Query Function:
- The
runQuery
function recursively issues queries to the MediaWiki API until there is no continuation string left in the response. It accumulates the list of languages from each response.
- The
-
Main Function:
- The
main
function starts the query process by callingrunQuery
with an empty list of languages and the initial query string.
- The
Second Part:
-
HTTP Request and Response:
- The
getRespons
function uses theNetwork.Browser
library to fetch the HTML response from the specified URL.
- The
-
Parsing HTML:
- The
mostPopLang
function parses the HTML response to extract the programming languages and their popularity. It uses theNetwork.URI
library to build the query URL and theText.XML.Light
library to parse the XML response from MediaWiki.
- The
-
Data Extraction:
- The
catMbr
function extracts the programming language name and popularity from the HTML response. - The
catNmbs
list contains the mapping from programming language names to their popularity.
- The
-
Pretty Printing:
- The
printFmt
function pretty-prints a single programming language and its popularity. - The
mostPopLang
function sorts the list of languages by popularity and then pretty-prints them.
- The
Source code in the haskell programming language
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import Network.HTTP.Base (urlEncode)
import Network.HTTP.Conduit (simpleHttp)
import Data.List (sortBy, groupBy)
import Data.Function (on)
import Data.Map (Map, toList)
-- Record representing a single language.
data Language =
Language {
name :: String,
quantity :: Int
} deriving (Show)
-- Make Language an instance of FromJSON for parsing of query response.
instance FromJSON Language where
parseJSON (Object p) = do
categoryInfo <- p .:? "categoryinfo"
let quantity = case categoryInfo of
Just ob -> ob .: "size"
Nothing -> return 0
name = p .: "title"
Language <$> name <*> quantity
-- Record representing entire response to query.
-- Contains collection of languages and optional continuation string.
data Report =
Report {
continue :: Maybe String,
languages :: Map String Language
} deriving (Show)
-- Make Report an instance of FromJSON for parsing of query response.
instance FromJSON Report where
parseJSON (Object p) = do
querycontinue <- p .:? "query-continue"
let continue
= case querycontinue of
Just ob -> fmap Just $
(ob .: "categorymembers") >>=
( .: "gcmcontinue")
Nothing -> return Nothing
languages = (p .: "query") >>= (.: "pages")
Report <$> continue <*> languages
-- Pretty print a single language
showLanguage :: Int -> Bool -> Language -> IO ()
showLanguage rank tie (Language languageName languageQuantity) =
let rankStr = show rank
in putStrLn $ rankStr ++ "." ++
replicate (4 - length rankStr) ' ' ++
(if tie then " (tie)" else " ") ++
" " ++ drop 9 languageName ++
" - " ++ show languageQuantity
-- Pretty print languages with common rank
showRanking :: (Int, [Language]) -> IO ()
showRanking (ranking, languages) =
mapM_ (showLanguage ranking $ length languages > 1) languages
-- Sort and group languages by rank, then pretty print them.
showLanguages :: [Language] -> IO ()
showLanguages allLanguages =
mapM_ showRanking $
zip [1..] $
groupBy ((==) `on` quantity) $
sortBy (flip compare `on` quantity) allLanguages
-- Mediawiki api style query to send to rosettacode.org
queryStr = "http://rosettacode.org/mw/api.php?" ++
"format=json" ++
"&action=query" ++
"&generator=categorymembers" ++
"&gcmtitle=Category:Programming%20Languages" ++
"&gcmlimit=100" ++
"&prop=categoryinfo"
-- Issue query to get a list of Language descriptions
runQuery :: [Language] -> String -> IO ()
runQuery ls query = do
Just (Report continue langs) <- decode <$> simpleHttp query
let accLanguages = ls ++ map snd (toList langs)
case continue of
-- If there is no continue string we are done so display the accumulated languages.
Nothing -> showLanguages accLanguages
-- If there is a continue string, recursively continue the query.
Just continueStr -> do
let continueQueryStr = queryStr ++ "&gcmcontinue=" ++ urlEncode continueStr
runQuery accLanguages continueQueryStr
main :: IO ()
main = runQuery [] queryStr
import Network.Browser
import Network.HTTP
import Network.URI
import Data.List
import Data.Maybe
import Text.XML.Light
import Control.Arrow
import Data.Ord
getRespons url = do
rsp <- Network.Browser.browse $ do
setAllowRedirects True
setOutHandler $ const (return ()) -- quiet
request $ getRequest url
return $ rspBody $ snd rsp
mostPopLang = do
rsp <-getRespons $ "http://www.rosettacode.org/w/api.php?action=query&list=" ++
"categorymembers&cmtitle=Category:Programming_Languages&cmlimit=500&format=xml"
mbrs <- getRespons "http://www.rosettacode.org/w/index.php?title=Special:Categories&limit=5000"
let xmls = onlyElems $ parseXML rsp
langs = concatMap (map ((\\"Category:"). fromJust.findAttr (unqual "title")). filterElementsName (== unqual "cm")) xmls
let catMbr = second (read.takeWhile(/=' '). drop 6). break (=='<'). drop 1. dropWhile(/='>') . drop 5
catNmbs :: [(String, Int)]
catNmbs = map catMbr $ filter (isPrefixOf "<li>") $ lines mbrs
printFmt (n,(l,m)) = putStrLn $ take 6 (show n ++ ". ") ++ (show m) ++ " " ++ l
toMaybe (a,b) =
case b of
Just x -> Just (a,x)
_ -> Nothing
mapM_ printFmt $ zip [1..] $ sortBy (flip (comparing snd))
$ mapMaybe (toMaybe. (id &&& flip lookup catNmbs)) langs
You may also check:How to resolve the algorithm Flow-control structures step by step in the IDL programming language
You may also check:How to resolve the algorithm Long year step by step in the Logo programming language
You may also check:How to resolve the algorithm Safe primes and unsafe primes step by step in the Maple programming language
You may also check:How to resolve the algorithm Babbage problem step by step in the EasyLang programming language
You may also check:How to resolve the algorithm Find the missing permutation step by step in the Ruby programming language