1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE OverloadedStrings #-}
5import Control.Applicative
7import Control.Monad.IO.Class
8import Control.Monad.Trans.Either
12import Data.Text (Text)
17import qualified Data.Text as T
18import qualified Data.Text.IO as T
21 "users" :> Get '[JSON] [UserSummary]
22 :<|> "user" :> Capture "username" Username :> Get '[JSON] UserDetailed
23 :<|> "packages" :> Get '[JSON] [Package]
27data UserSummary = UserSummary
28 { summaryUsername :: Username
29 , summaryUserid :: Int
32instance FromJSON UserSummary where
33 parseJSON (Object o) =
34 UserSummary <$> o .: "username"
41data UserDetailed = UserDetailed
42 { username :: Username
45 } deriving (Eq, Show, Generic)
47instance FromJSON UserDetailed
49newtype Package = Package { packageName :: Text }
50 deriving (Eq, Show, Generic)
52instance FromJSON Package
54hackageAPI :: Proxy HackageAPI
57getUsers :: EitherT ServantError IO [UserSummary]
58getUser :: Username -> EitherT ServantError IO UserDetailed
59getPackages :: EitherT ServantError IO [Package]
60getUsers :<|> getUser :<|> getPackages = client hackageAPI $ BaseUrl Http "hackage.haskell.org" 80
63main = print =<< uselessNumbers
65uselessNumbers :: IO (Either ServantError ())
66uselessNumbers = runEitherT $ do
68 liftIO . putStrLn $ show (length users) ++ " users"
71 putStrLn "Enter a valid hackage username"
73 userDetailed <- (getUser user)
74 liftIO . T.putStrLn $ user <> " maintains " <> T.pack (show (length $ groups userDetailed)) <> " packages"
76 packages <- getPackages
77 let monadPackages = filter (isMonadPackage . packageName) packages
78 liftIO . putStrLn $ show (length monadPackages) ++ " monad packages"
80 where isMonadPackage = T.isInfixOf "monad"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list