Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
module Library
) where
import qualified Data.Map as Map
data Author = Author String deriving (Show, Eq, Ord)
data Book = Book String deriving (Show, Eq, Ord)
type AuthorIndex = Map.Map Author [Book]
type BookIndex = Map.Map Book [Author]
data Catalog =
Catalog {
authorIndex :: AuthorIndex,
bookIndex :: BookIndex
} deriving (Show)
-- class for determining if a book or author is
-- in the catalog
class Catalogued a where
catalogued :: a -> Catalog -> Bool
-- ********************************
-- API (exported) methods
-- ********************************
addAuthor :: Author -> Catalog -> Catalog
addAuthor a c@(Catalog as bs) =
c { authorIndex = insertUnlessPresent a [] as }
addBook :: Book -> Catalog -> Catalog
addBook b c@(Catalog as bs) =
c { bookIndex = insertUnlessPresent b [] bs }
-- associate an author "a" with a book "b"
-- this will update both the book and author
-- indexes in a given catalog
associate :: Author -> Book -> Catalog -> Catalog
associate a b (Catalog as bs) = Catalog as' bs'
as' = Map.alter (addValue b) a as
bs' = Map.alter (addValue a) b bs
addValue x Nothing = Just [x]
addValue x (Just ys) = Just (x:ys)
-- Return all the authors for a book as listed in a catalog
authors :: Book -> Catalog -> Maybe [Author]
authors b c = Map.lookup b (bookIndex c)
-- return all the books written by an author as listed in a catalog
books :: Author -> Catalog -> Maybe [Book]
books a c = Map.lookup a (authorIndex c)
-- returns True if an author or book is in
-- the given catalog
instance Catalogued Author where
catalogued a c = a `Map.member` (authorIndex c)
instance Catalogued Book where
catalogued b c = b `Map.member` (bookIndex c)
-- ********************************
-- private (unexported) methods
-- ********************************
insertUnlessPresent k v m
| k `Map.member` m = m
| otherwise = Map.insert k v m
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment