Created
April 9, 2014 04:34
-
-
Save heather-alexander/10226376 to your computer and use it in GitHub Desktop.
Finite map with functional dependencies
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# 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