TotalMap: A total map datatype

[ control, library, mit ] [ Propose Tags ]

Provides a datatype representing a total map using an enum type as keys


[Skip to Readme]
Versions [faq] 0.1.0.0
Change log ChangeLog.md
Dependencies adjunctions (==4.4.*), base (>=4.8 && <4.13), distributive (>=0.5 && <0.7), generics-sop (>=0.3 && <0.5), lens (>=4.16 && <4.20) [details]
License MIT
Author Ed Wastell
Maintainer ed@wastell.co.uk
Category Control
Source repo head: git clone https://github.com/edwardwas/TotalMap
Uploaded by edwardwas at Wed Nov 14 13:42:55 UTC 2018
Distributions LTSHaskell:0.1.0.0, NixOS:0.1.0.0, Stackage:0.1.0.0
Downloads 68 total (31 in the last 30 days)
Rating 2.0 (votes: 1) [estimated by rule of succession]
Your Rating
  • λ
  • λ
  • λ
Status Hackage Matrix CI
Docs available [build log]
Last success reported on 2018-11-14 [all 1 reports]

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

For package maintainers and hackage trustees


Readme for TotalMap-0.1.0.0

[back to package description]

Total Map

Often one may have an enum type representing all possible keys of something, and wishes to store some data associated with it. In this case you have two options - use a function or a Map from containers. A function works, but can be difficult to update and has not Eq or Show instances. A map solves this issue, but gives no guarantee that a key has associated data - all functions become partial. This library offers a different way of solving this problem.

A TotalMap k a is a total mapping from a key of type k to a value of type a; each k will have exactly one a. It permits many instances, including Show and Eq.

Example

Let us create and example. We start with some imports and some language pragmas.

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}

import TotalMap

import Control.Lens
import Control.Monad (void)
import Data.Functor.Rep (tabulate)
import qualified GHC.Generics as GHC (Generic)
import Generics.SOP

TotalMap uses generics-sop internally, so we require it as an import. We also require some typeclasses introduced by lens.

For our example, we shall create a dummy program for sending out peoples fortunes based on their star sign. We shall create a star sign type.

data StarSign
  = Aries
  | Taurus
  | Gemini
  | Cancer
  | Leo
  | Virgo
  | Scorpio
  | Sagittarius
  | Capricorn
  | Aquarius
  | Pisces
  deriving (Eq, Show, GHC.Generic, Generic)

Note the derivation of both GHC.Generic and Generic. These are required to guarantee that StarSign's constructors take no imports.

We have a list of people, and we can partition them based on their star sign.

data Date = Date
  { month :: Int
  , day :: Int
  } deriving (Eq, Show)

data Person = Person
  { name :: String
  , email :: String
  , birthDate :: Date
  } deriving (Eq, Show)

signFromDate :: Date -> StarSign
signFromDate = undefined

peopleSign :: [Person] -> TotalMap StarSign [Person]
peopleSign ps = tabulate $ \s -> filter ((==) s . signFromDate . birthDate) ps

We could send people an email with their fortune.

sendFortune :: String -> String -> StarSign -> IO ()
sendFortune = undefined

sendFortunes :: [Person] -> IO ()
sendFortunes =
  void .
  itraverse (\sign -> mapM_ (\p -> sendFortune (name p) (email p) sign)) .
  peopleSign

Future

  • Come up with a better example
  • Is Lens necessary. It is useful, but it is a huge dependency.

The following is required to make tests compile.

main :: IO ()
main = return ()