Skip to content

Instantly share code, notes, and snippets.

@heather-alexander
Created April 9, 2014 04:34
Show Gist options
  • Save heather-alexander/10226376 to your computer and use it in GitHub Desktop.
Save heather-alexander/10226376 to your computer and use it in GitHub Desktop.
Finite map with functional dependencies
{-# LANGUAGE FunctionalDependencies, FlexibleInstances #-}
import Data.Maybe (fromJust, isJust)
-- Finite map class suggested in "Type Classes with Functional Dependencies" (Mark Philip Jones, 2000).
class FiniteMap i e fm | fm -> i e where
emptyFM :: fm
look :: i -> fm -> Maybe e
extend :: i -> e -> fm -> fm
-- Given a function (Int -> Maybe a) and an association list,
-- add the mappings in the list to the map.
extendL :: FiniteMap i e fm => fm -> [(i,e)] -> fm
extendL fm = foldr (uncurry extend) fm
-- Make a map out of an association list.
-- (Since the map pretty much just scans over the list,
-- doing this isn't incredibly useful or very efficient at all.
-- But it's fun syntax).
fromL :: FiniteMap i e fm => [(i,e)] -> fm
fromL = extendL emptyFM
-- Instance for (i -> Maybe e).
-- empty and look are straightforward with Maybe
-- extend prepends an new input mapping to a finite map,
-- resulting in a map that scans that list before looking in the original map.
instance (Eq i) => FiniteMap i e (i -> Maybe e) where
emptyFM = const Nothing
look i fm = fm i
extend i e fm = \j -> if j == i then Just e else fm j
-- occlude combines two maps, using the result from the first if it is available.
-- Starting with some other partially defined function i -> Maybe e instead of emptyFM
-- the function can be extended with different results.
occlude :: FiniteMap i e fm => fm -> fm -> (i -> Maybe e)
m1 `occlude` m2 = \i -> let r1 = look i m1 in if isJust r1 then r1 else look i m2
-- Mostly accurate integer halving function
halve :: Int -> Int
halve = fromJust . (fromL [(5,3), (8,7)] `occlude` (Just . (`div` 2)))
-- Examples
ex_mm = fromJust $ (extend 2 "this" emptyFM) 2
ex_fl1 = fromJust $ fromL [(3, "this"), (4, "that")] 5
ex_fl2 = fromJust $ fromL [(3, "this"), (4, "that")] 4
ex_occlude = fromJust $ mapM (fromL [(3,5),(2,4)] `occlude` Just) [1..10]
ex_halve = map halve [1..20]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment