Commit 1169979f authored by Michael Hanus's avatar Michael Hanus
Browse files

Tools updated

parent 5a5d0e87
......@@ -10,6 +10,7 @@ optimize/.cpm/packages/cass-2.0.0
optimize/.cpm/packages/cass-analysis-2.0.0
optimize/.cpm/packages/csv-1.0.0
optimize/.cpm/packages/currypath-0.0.1
optimize/.cpm/packages/finite-map-0.0.1
optimize/.cpm/packages/flatcurry-2.0.0
optimize/.cpm/packages/frontend-exec-0.0.1
optimize/.cpm/packages/propertyfile-0.0.1
......
------------------------------------------------------------------------------
--- Library defining natural numbers in Peano representation and
--- some operations on this representation.
---
--- @author Michael Hanus
--- @version May 2017
--- @category general
------------------------------------------------------------------------------
module Nat
( Nat(..), fromNat, toNat, add, sub, mul, leq
) where
--- Natural numbers defined in Peano representation.
data Nat = Z | S Nat
deriving (Eq,Show)
--- Transforms a natural number into a standard integer.
fromNat :: Nat -> Int
fromNat Z = 0
fromNat (S n) = 1 + fromNat n
--- Transforms a standard integer into a natural number.
toNat :: Int -> Nat
toNat n | n == 0 = Z
| n > 0 = S (toNat (n-1))
--- Addition on natural numbers.
add :: Nat -> Nat -> Nat
add Z n = n
add (S m) n = S(add m n)
--- Subtraction defined by reversing addition.
sub :: Nat -> Nat -> Nat
sub x y | add y z == x = z where z free
--- Multiplication on natural numbers.
mul :: Nat -> Nat -> Nat
mul Z _ = Z
mul (S m) n = add n (mul m n)
-- less-or-equal predicated on natural numbers:
leq :: Nat -> Nat -> Bool
leq Z _ = True
leq (S _) Z = False
leq (S x) (S y) = leq x y
......@@ -32,8 +32,10 @@ readAndTestEqualFcy mod = do
renameFile modbak modcurry
let abstractequal = prog1 == prog2
unless abstractequal $ do
putStrLn $ "Original AbstractCurry program: " ++ show prog1
putStrLn $ "Pretty printed AbstractCurry program: " ++ show prog2
putStrLn $ unlines
[ "Differences in programs occurred:"
, "Original AbstractCurry program:", show prog1
, "Pretty printed AbstractCurry program:", show prog2 ]
return abstractequal
-- Strictly read a AbstractCurry program in order to avoid race conditions
......@@ -47,4 +49,4 @@ testAbstractCurryPretty_rev =
(readAndTestEqualFcy "Rev") `returns` True
testAbstractCurryPretty_TestAbstractCurry =
(readAndTestEqualFcy "TestAbstractCurry") `returns` True
(readAndTestEqualFcy "Nat") `returns` True
......@@ -9,6 +9,7 @@
"dependencies": {
"base" : ">= 1.0.0, < 2.0.0",
"currypath" : ">= 0.0.1",
"finite-map": ">= 0.0.1",
"flatcurry" : ">= 2.0.0",
"scc" : ">= 0.0.1"
},
......
......@@ -2,7 +2,7 @@
--- This module defines a datatype to represent the analysis information.
---
--- @author Heiko Hoffmann, Michael Hanus
--- @version January 2015
--- @version January 2019
-----------------------------------------------------------------------
module Analysis.ProgInfo
......@@ -14,8 +14,9 @@ module Analysis.ProgInfo
) where
import Directory (removeFile)
import FiniteMap
import FilePath ((<.>))
import Data.FiniteMap
import FlatCurry.Types
import XML
......
......@@ -10,6 +10,7 @@
"base" : ">= 1.0.0, < 2.0.0",
"cass-analysis" : ">= 2.0.0",
"currypath" : ">= 0.0.1",
"finite-map" : ">= 0.0.1",
"flatcurry" : ">= 2.0.0",
"propertyfile" : ">= 0.0.1",
"redblacktree" : ">= 0.0.1",
......
......@@ -3,12 +3,11 @@
--- In particular, it contains some simple fixpoint computations.
---
--- @author Heiko Hoffmann, Michael Hanus
--- @version December 2018
--- @version January 2019
--------------------------------------------------------------------------
module CASS.WorkerFunctions where
import FiniteMap
import IOExts
import List ( partition )
import Maybe ( fromJust )
......@@ -21,6 +20,7 @@ import Analysis.Types ( Analysis(..), isSimpleAnalysis, isCombinedAnalysis
import Analysis.ProgInfo ( ProgInfo, combineProgInfo, emptyProgInfo
, publicProgInfo, lookupProgInfo, lists2ProgInfo
, equalProgInfo, publicListFromProgInfo, showProgInfo )
import Data.FiniteMap
import FlatCurry.Types
import FlatCurry.Files
import FlatCurry.Goodies
......
Copyright (c) 2019, Michael Hanus
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the names of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
finite-map
==========
This package contains the library `Data.Map` implementing
finite maps, i.e., efficient purely functional data structures
to store a mapping from keys to values.
For compatibility reason, it also contains an old but deprecated
library `Data.FiniteMap`.
{
"name": "finite-map",
"version": "0.0.1",
"author": "Michael Hanus <mh@informatik.uni-kiel.de>",
"synopsis": "Library implementing finite maps (efficient mappings from keys to values)",
"category": [ "Data" ],
"license": "BSD-3-Clause",
"licenseFile": "LICENSE",
"dependencies": {
"base" : ">= 1.0.0, < 2.0.0",
"random" : ">= 0.0.1"
},
"compilerCompatibility": {
"pakcs": ">= 2.0.0",
"kics2": ">= 2.0.0"
},
"exportedModules": [ "Data.Map", "Data.FiniteMap" ],
"testsuite": [
{ "src-dir": "src",
"modules": [ "Data.Map", "Data.FiniteMap" ]
},
{ "src-dir": "test",
"modules": [ "TestFiniteMap" ]
}
],
"source": {
"git": "https://git.ps.informatik.uni-kiel.de/curry-packages/finite-map.git",
"tag": "$version"
}
}
-----------------------------------------------------------------------------
--- *IMPORTANT NOTE*: This library is deprecated and included only
--- for compatibility with older programs. Use library `Data.Map` instead!
---
--- A finite map is an efficient purely functional data structure
--- to store a mapping from keys to values.
--- In order to store the mapping efficiently, an irreflexive(!) order predicate
--- has to be given, i.e., the order predicate `le` should not satisfy
--- `(le x x)` for some key `x`.
---
--- Example: To store a mapping from `Int -> String`, the finite map needs
--- a Boolean predicate like `(<)`.
--- This version was ported from a corresponding Haskell library
---
--- @author Frank Huch, Bernd Brassel
--- @version January 2019
-----------------------------------------------------------------------------
module Data.FiniteMap (
FM, -- abstract type
emptyFM,
unitFM,
listToFM,
addToFM,
addToFM_C,
addListToFM,
addListToFM_C,
delFromFM,
delListFromFM,
splitFM,
plusFM,
plusFM_C,
minusFM,
intersectFM,
intersectFM_C,
foldFM,
mapFM,
filterFM,
sizeFM,
eqFM,
isEmptyFM,
elemFM,
lookupFM,
lookupWithDefaultFM,
keyOrder,
fmToList,
keysFM,
eltsFM,
fmSortBy,
minFM,maxFM,updFM, fmToListPreOrder,
showFM, readFM
) where
import Maybe
import ReadShowTerm (readQTerm, showQTerm)
--- order predicates are boolean
type LeKey key = key -> key -> Bool
-----------------------------------------------
-- BUILDING finite maps
-----------------------------------------------
--- The empty finite map.
--- @param le an irreflexive order predicate on the keys.
--- @result an empty finite map
emptyFM :: (LeKey key) -> FM key _
emptyFM le = FM le EmptyFM
--- Construct a finite map with only a single element.
--- @param le an irreflexive order predicate on the keys.
--- @param key key of
--- @param elt the single element to form
--- @result a finite map with only a single element
unitFM :: (LeKey key) -> key -> elt -> FM key elt
unitFM le key elt = FM le (unitFM' key elt)
unitFM' :: key -> elt -> FiniteMap key elt
unitFM' key elt = BranchFM key elt 1 EmptyFM EmptyFM
--- Builts a finite map from given list of tuples (key,element).
--- For multiple occurences of key, the last corresponding
--- element of the list is taken.
--- @param le an irreflexive order predicate on the keys.
listToFM :: Eq key => (LeKey key) -> [(key,elt)] -> FM key elt
listToFM le = addListToFM (emptyFM le)
-----------------------------------------------
-- ADDING AND DELETING
-----------------------------------------------
--- Throws away any previous binding and stores the new one given.
addToFM :: Eq key => FM key elt -> key -> elt -> FM key elt
addToFM (FM le fm) key elt = FM le (addToFM' le fm key elt)
addToFM' :: Eq key => (LeKey key) -> FiniteMap key elt -> key -> elt
-> FiniteMap key elt
addToFM' le fm key elt = addToFM_C' le (\ _ new -> new) fm key elt
addToFM_C' :: Eq key => (LeKey key) -> (elt -> elt -> elt)
-> FiniteMap key elt -> key -> elt -> FiniteMap key elt
addToFM_C' _ _ EmptyFM key elt = unitFM' key elt
addToFM_C' le combiner (BranchFM key elt size fm_l fm_r) new_key new_elt
= if le new_key key
then mkBalBranch key elt (addToFM_C' le combiner fm_l new_key new_elt) fm_r
else
if new_key==key
then BranchFM new_key (combiner elt new_elt) size fm_l fm_r
else mkBalBranch key elt fm_l (addToFM_C' le combiner fm_r new_key new_elt)
--- Throws away any previous bindings and stores the new ones given.
--- The items are added starting with the first one in the list
addListToFM :: Eq key => FM key elt -> [(key,elt)] -> FM key elt
addListToFM (FM le fm) key_elt_pairs =
FM le (addListToFM' le fm key_elt_pairs)
addListToFM' :: Eq key => (LeKey key) -> FiniteMap key elt
-> [(key, elt)] -> FiniteMap key elt
addListToFM' le fm key_elt_pairs =
addListToFM_C' le (\ _ new -> new) fm key_elt_pairs
addListToFM_C' :: Eq key => (LeKey key) -> (elt -> elt -> elt)
-> FiniteMap key elt -> [(key, elt)] -> FiniteMap key elt
addListToFM_C' le combiner fm key_elt_pairs
= foldl add fm key_elt_pairs -- foldl adds from the left
where
add fmap (key,elt) = addToFM_C' le combiner fmap key elt
--- Instead of throwing away the old binding,
--- addToFM_C combines the new element with the old one.
--- @param combiner a function combining to elements
--- @param fm a finite map
--- @param key the key of the elements to be combined
--- @param elt the new element
--- @result a modified finite map
addToFM_C :: Eq key => (elt -> elt -> elt) -> FM key elt -> key -> elt
-> FM key elt
addToFM_C combiner (FM le fm) key elt =
FM le (addToFM_C' le combiner fm key elt)
--- Combine with a list of tuples (key,element), cf. addToFM_C
addListToFM_C :: Eq key => (elt -> elt -> elt) -> FM key elt -> [(key,elt)]
-> FM key elt
addListToFM_C combiner (FM le fm) key_elt_pairs =
FM le (addListToFM_C' le combiner fm key_elt_pairs)
--- Deletes key from finite map.
--- Deletion doesn't complain if you try to delete something
--- which isn't there
delFromFM :: Eq key => FM key elt -> key -> FM key elt
delFromFM (FM le fm) del_key = FM le (delFromFM' le fm del_key)
delFromFM' :: Eq key => (LeKey key) -> FiniteMap key elt -> key
-> FiniteMap key elt
delFromFM' _ EmptyFM _ = EmptyFM
delFromFM' le (BranchFM key elt _ fm_l fm_r) del_key
= if le del_key key
then mkBalBranch key elt (delFromFM' le fm_l del_key) fm_r
else
if del_key==key
then glueBal le fm_l fm_r
else mkBalBranch key elt fm_l (delFromFM' le fm_r del_key)
--- Deletes a list of keys from finite map.
--- Deletion doesn't complain if you try to delete something
--- which isn't there
delListFromFM :: Eq key => FM key elt -> [key] -> FM key elt
delListFromFM (FM le fm) keys = FM le (foldl (delFromFM' le) fm keys)
--- Applies a function to element bound to given key.
updFM :: Eq a => FM a b -> a -> (b -> b) -> FM a b
updFM (FM lt fm) i f = FM lt (upd fm)
where
upd EmptyFM = EmptyFM
upd (BranchFM k x h l r)
| i == k = BranchFM k (f x) h l r
| lt i k = BranchFM k x h (upd l) r
| otherwise = BranchFM k x h l (upd r)
--- Combines delFrom and lookup.
splitFM :: Eq a => FM a b -> a -> Maybe (FM a b,(a,b))
splitFM g v = maybe Nothing (\x->Just (delFromFM g v,(v,x))) (lookupFM g v)
-------------------------------------------------
-- COMBINING finite maps
-------------------------------------------------
--- Efficiently add key/element mappings of two maps into a single one.
--- Bindings in right argument shadow those in the left
plusFM :: Eq key => FM key elt -> FM key elt -> FM key elt
plusFM (FM le1 fm1) (FM _ fm2) = FM le1 (plusFM' le1 fm1 fm2)
plusFM' :: Eq key => (LeKey key)
-> FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt
plusFM' _ EmptyFM fm2 = fm2
plusFM' _ (BranchFM split_key1 elt1 s1 left1 right1) EmptyFM =
(BranchFM split_key1 elt1 s1 left1 right1)
plusFM' le (BranchFM split_key1 elt1 s1 left1 right1)
(BranchFM split_key elt2 _ left right)
= mkVBalBranch le split_key elt2 (plusFM' le lts left) (plusFM' le gts right)
where
fm1 = BranchFM split_key1 elt1 s1 left1 right1
lts = splitLT le fm1 split_key
gts = splitGT le fm1 split_key
--- Efficiently combine key/element mappings of two maps into a single one,
--- cf. addToFM_C
plusFM_C :: Eq key => (elt -> elt -> elt)
-> FM key elt -> FM key elt -> FM key elt
plusFM_C combiner (FM le1 fm1) (FM _ fm2) =
FM le1 (plusFM_C' le1 combiner fm1 fm2)
plusFM_C' :: Eq key => LeKey key -> (elt -> elt -> elt)
-> FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt
plusFM_C' _ _ EmptyFM fm2 = fm2
plusFM_C' _ _ (BranchFM split_key1 elt1 s1 left1 right1) EmptyFM =
BranchFM split_key1 elt1 s1 left1 right1
plusFM_C' le combiner (BranchFM split_key1 elt1 s1 left1 right1)
(BranchFM split_key elt2 _ left right)
= mkVBalBranch le split_key new_elt
(plusFM_C' le combiner lts left)
(plusFM_C' le combiner gts right)
where
fm1 = BranchFM split_key1 elt1 s1 left1 right1
lts = splitLT le fm1 split_key
gts = splitGT le fm1 split_key
new_elt = case lookupFM' le fm1 split_key of
Nothing -> elt2
Just elt1' -> combiner elt1' elt2
--- (minusFM a1 a2) deletes from a1 any bindings which are bound in a2
minusFM :: Eq key => FM key elt -> FM key elt -> FM key elt
minusFM (FM le1 fm1) (FM _ fm2) = FM le1 (minusFM' le1 fm1 fm2)
minusFM' :: Eq key => (LeKey key)
-> FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt
minusFM' _ EmptyFM _ = EmptyFM
minusFM' _ (BranchFM split_key1 elt1 s1 left1 right1) EmptyFM =
BranchFM split_key1 elt1 s1 left1 right1
minusFM' le (BranchFM split_key1 elt1 s1 left1 right1)
(BranchFM split_key _ _ left right)
= glueVBal le (minusFM' le lts left) (minusFM' le gts right)
-- The two can be way different, so we need glueVBal
where
fm1 = BranchFM split_key1 elt1 s1 left1 right1
lts = splitLT le fm1 split_key -- NB gt and lt, so the equal ones
gts = splitGT le fm1 split_key -- are not in either.
--- Filters only those keys that are bound in both of the given maps.
--- The elements will be taken from the second map.
intersectFM :: Eq key => FM key elt -> FM key elt -> FM key elt
intersectFM (FM le1 fm1) (FM _ fm2) = FM le1 (intersectFM' le1 fm1 fm2)
intersectFM' :: Eq key => LeKey key
-> FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt
intersectFM' le fm1 fm2 = intersectFM_C' le (\ _ right -> right) fm1 fm2
--- Filters only those keys that are bound in both of the given maps
--- and combines the elements as in addToFM_C.
intersectFM_C :: Eq key => (elt -> elt2 -> elt3) -> FM key elt -> FM key elt2
-> FM key elt3
intersectFM_C combiner (FM le1 fm1) (FM _ fm2) =
FM le1 (intersectFM_C' le1 combiner fm1 fm2)
intersectFM_C' :: Eq key => LeKey key -> (elt -> elt2 -> elt3)
-> FiniteMap key elt -> FiniteMap key elt2 -> FiniteMap key elt3
intersectFM_C' _ _ _ EmptyFM = EmptyFM
intersectFM_C' _ _ EmptyFM (BranchFM _ _ _ _ _) = EmptyFM
intersectFM_C' le combiner (BranchFM split_key1 elt1 s1 left1 right1)
(BranchFM split_key elt2 _ left right)
| isJust maybe_elt1 -- split_elt *is* in intersection
= mkVBalBranch le split_key (combiner elt1' elt2)
(intersectFM_C' le combiner lts left)
(intersectFM_C' le combiner gts right)
| otherwise -- split_elt is *not* in intersection
= glueVBal le (intersectFM_C' le combiner lts left)
(intersectFM_C' le combiner gts right)
where
fm1 = BranchFM split_key1 elt1 s1 left1 right1
lts = splitLT le fm1 split_key -- NB gt and lt, so the equal ones
gts = splitGT le fm1 split_key -- are not in either.
maybe_elt1 = lookupFM' le fm1 split_key
Just elt1' = maybe_elt1
-------------------------------------------------------------
-- MAPPING, FOLDING, FILTERING on finite maps
-------------------------------------------------------------
--- Folds finite map by given function.
foldFM :: (key -> elt -> a -> a) -> a -> FM key elt -> a
foldFM k z (FM le fm) = foldFM' le k z fm
foldFM' :: LeKey key -> (key -> elt -> a -> a) -> a -> FiniteMap key elt -> a
foldFM' _ _ z EmptyFM = z
foldFM' le k z (BranchFM key elt _ fm_l fm_r)
= foldFM' le k (k key elt (foldFM' le k z fm_r)) fm_l
--- Applies a given function on every element in the map.
mapFM :: (key -> elt1 -> elt2) -> FM key elt1 -> FM key elt2
mapFM f (FM le fm) = FM le (mapFM' le f fm)
mapFM' :: LeKey key -> (key -> elt1 -> elt2)
-> FiniteMap key elt1 -> FiniteMap key elt2
mapFM' _ _ EmptyFM = EmptyFM
mapFM' le f (BranchFM key elt size fm_l fm_r)
= BranchFM key (f key elt) size (mapFM' le f fm_l) (mapFM' le f fm_r)
--- Yields a new finite map with only those key/element pairs matching the
--- given predicate.
filterFM :: Eq key => (key -> elt -> Bool) -> FM key elt -> FM key elt
filterFM p (FM le fm) = FM le (filterFM' le p fm)
filterFM' :: Eq key => LeKey key -> (key -> elt -> Bool)
-> FiniteMap key elt -> FiniteMap key elt
filterFM' _ _ EmptyFM = EmptyFM
filterFM' le p (BranchFM key elt _ fm_l fm_r)
| p key elt -- Keep the item
= mkVBalBranch le key elt (filterFM' le p fm_l) (filterFM' le p fm_r)
| otherwise -- Drop the item
= glueVBal le (filterFM' le p fm_l) (filterFM' le p fm_r)
-----------------------------------------------------
-- INTERROGATING finite maps
-----------------------------------------------------
--- How many elements does given map contain?
sizeFM :: FM _ _ -> Int
sizeFM (FM _ EmptyFM) = 0
sizeFM (FM _ (BranchFM _ _ size _ _)) = size
sizeFM' :: FiniteMap _ _ -> Int
sizeFM' EmptyFM = 0
sizeFM' (BranchFM _ _ size _ _) = size
--- Do two given maps contain the same key/element pairs?
eqFM :: (Eq key, Eq elt) => FM key elt -> FM key elt -> Bool
fm_1 `eqFM` fm_2 =
(sizeFM fm_1 == sizeFM fm_2) && -- quick test
(fmToList fm_1 == fmToList fm_2)
--- Is the given finite map empty?
isEmptyFM :: FM _ _ -> Bool
isEmptyFM fm = sizeFM fm == 0
--- Does given map contain given key?
elemFM :: Eq key => key -> FM key _ -> Bool
key `elemFM` fm = isJust (lookupFM fm key)
--- Retrieves element bound to given key
lookupFM :: Eq key => FM key elt -> key -> Maybe elt
lookupFM (FM le fm) key = lookupFM' le fm key
lookupFM' :: Eq key => LeKey key -> FiniteMap key elt -> key -> Maybe elt
lookupFM' _ EmptyFM _ = Nothing
lookupFM' le (BranchFM key elt _ fm_l fm_r) key_to_find
= if le key_to_find key
then lookupFM' le fm_l key_to_find
else if key_to_find==key
then Just elt
else lookupFM' le fm_r key_to_find
--- Retrieves element bound to given key.
--- If the element is not contained in map, return
--- default value.
lookupWithDefaultFM :: Eq key => FM key elt -> elt -> key -> elt
lookupWithDefaultFM fm deflt key
= case lookupFM fm key of
Nothing -> deflt
Just elt -> elt
--- Retrieves the ordering on which the given finite map is built.
keyOrder :: FM key _ -> (key->key->Bool)
keyOrder (FM lt _) = lt
--- Retrieves the smallest key/element pair in the finite map
--- according to the basic key ordering.
minFM :: FM a b -> Maybe (a,b)
minFM = min . tree
where
min EmptyFM = Nothing
min (BranchFM k x _ l _) | isBranchFM l = min l
| otherwise = Just (k,x)
--- Retrieves the greatest key/element pair in the finite map
--- according to the basic key ordering.
maxFM :: FM a b -> Maybe (a,b)
maxFM = max . tree
where
max EmptyFM = Nothing
max (BranchFM k x _ _ r) | isBranchFM r = max r
| otherwise = Just (k,x)
----------------------------------------------------
-- LISTIFYING: transform finite maps to lists
----------------------------------------------------
--- Builds a list of key/element pairs. The list is ordered
--- by the initially given irreflexive order predicate on keys.
fmToList :: FM key elt -> [(key,elt)]
fmToList fm = foldFM (\ key elt rest -> (key,elt) : rest) [] fm
--- Retrieves a list of keys contained in finite map.