packages feed

FiniteMap (empty) → 0.1

raw patch · 4 files changed

+717/−0 lines, 4 filesdep +basedep +haskell98build-type:Customsetup-changed

Dependencies added: base, haskell98

Files

+ Data/FiniteMap.lhs view
@@ -0,0 +1,670 @@+%+% (c) The AQUA Project, Glasgow University, 1994-1996+%+\section[FiniteMap]{An implementation of finite maps}++``Finite maps'' are the heart of the compiler's+lookup-tables/environments and its implementation of sets.  Important+stuff!++This code is derived from that in the paper:+\begin{display}+	S Adams+	"Efficient sets: a balancing act"+	Journal of functional programming 3(4) Oct 1993, pp553-562+\end{display}++The code is SPECIALIZEd to various highly-desirable types (e.g., Id)+near the end (only \tr{#ifdef COMPILING_GHC}).++\begin{code}+++++++++++++++module Data.FiniteMap (+	FiniteMap,		-- abstract type++	emptyFM, unitFM, listToFM,++	addToFM,+	addToFM_C,+	addListToFM,+	addListToFM_C,+	delFromFM ,+	delListFromFM,++	plusFM,+	plusFM_C,+	minusFM,+	foldFM,++	intersectFM ,+	intersectFM_C ,+	mapFM , mapMaybeFM , filterFM ,++	sizeFM, isEmptyFM, elemFM, lookupFM, lookupWithDefaultFM,++	fmToList, keysFM, eltsFM+++    ) where++import Maybe ( isJust )+++++-- SIGH: but we use unboxed "sizes"...++++\end{code}+++%************************************************************************+%*									*+\subsection{The signature of the module}+%*									*+%************************************************************************++\begin{code}+--	BUILDING+emptyFM		:: FiniteMap key elt+unitFM		:: key -> elt -> FiniteMap key elt+listToFM	:: (Ord key {--}) => [(key,elt)] -> FiniteMap key elt+			-- In the case of duplicates, the last is taken+++--	ADDING AND DELETING+		   -- Throws away any previous binding+		   -- In the list case, the items are added starting with the+		   -- first one in the list+addToFM		:: (Ord key {--}) => FiniteMap key elt -> key -> elt  -> FiniteMap key elt+addListToFM	:: (Ord key {--}) => FiniteMap key elt -> [(key,elt)] -> FiniteMap key elt++		   -- Combines with previous binding+		   -- In the combining function, the first argument is the "old" element,+		   -- while the second is the "new" one.+addToFM_C	:: (Ord key {--}) => (elt -> elt -> elt)+			   -> FiniteMap key elt -> key -> elt+			   -> FiniteMap key elt+addListToFM_C	:: (Ord key {--}) => (elt -> elt -> elt)+			   -> FiniteMap key elt -> [(key,elt)]+			   -> FiniteMap key elt++		   -- Deletion doesn't complain if you try to delete something+		   -- which isn't there+delFromFM	:: (Ord key {--}) => FiniteMap key elt -> key   -> FiniteMap key elt+delListFromFM	:: (Ord key {--}) => FiniteMap key elt -> [key] -> FiniteMap key elt++--	COMBINING+		   -- Bindings in right argument shadow those in the left+plusFM		:: (Ord key {--}) => FiniteMap key elt -> FiniteMap key elt+			   -> FiniteMap key elt++		   -- Combines bindings for the same thing with the given function+plusFM_C	:: (Ord key {--}) => (elt -> elt -> elt)+			   -> FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt++minusFM		:: (Ord key {--}) => FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt+		   -- (minusFM a1 a2) deletes from a1 any bindings which are bound in a2++intersectFM	:: (Ord key {--}) => FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt+intersectFM_C	:: (Ord key {--}) => (elt1 -> elt2 -> elt3)+			   -> FiniteMap key elt1 -> FiniteMap key elt2 -> FiniteMap key elt3++--	MAPPING, FOLDING, FILTERING+foldFM		:: (key -> elt -> a -> a) -> a -> FiniteMap key elt -> a+mapFM		:: (key -> elt1 -> elt2) -> FiniteMap key elt1 -> FiniteMap key elt2+filterFM	:: (Ord key {--}) => (key -> elt -> Bool)+			   -> FiniteMap key elt -> FiniteMap key elt+mapMaybeFM      :: (Ord key {--})+                => (key -> elt1 -> Maybe elt2)+                -> FiniteMap key elt1+		-> FiniteMap key elt2++--	INTERROGATING+sizeFM		:: FiniteMap key elt -> Int+isEmptyFM	:: FiniteMap key elt -> Bool++elemFM		:: (Ord key {--}) => key -> FiniteMap key elt -> Bool+lookupFM	:: (Ord key {--}) => FiniteMap key elt -> key -> Maybe elt+lookupWithDefaultFM+		:: (Ord key {--}) => FiniteMap key elt -> elt -> key -> elt+		-- lookupWithDefaultFM supplies a "default" elt+		-- to return for an unmapped key++--	LISTIFYING+fmToList	:: FiniteMap key elt -> [(key,elt)]+keysFM		:: FiniteMap key elt -> [key]+eltsFM		:: FiniteMap key elt -> [elt]+\end{code}++%************************************************************************+%*									*+\subsection{The @FiniteMap@ data type, and building of same}+%*									*+%************************************************************************++Invariants about @FiniteMap@:+\begin{enumerate}+\item+all keys in a FiniteMap are distinct+\item+all keys in left  subtree are $<$ key in Branch and+all keys in right subtree are $>$ key in Branch+\item+size field of a Branch gives number of Branch nodes in the tree+\item+size of left subtree is differs from size of right subtree by a+factor of at most \tr{sIZE_RATIO}+\end{enumerate}++\begin{code}+data FiniteMap key elt+  = EmptyFM+  | Branch key elt	    	-- Key and elt stored here+    Int{-STRICT-}	-- Size >= 1+    (FiniteMap key elt)	    	-- Children+    (FiniteMap key elt)+\end{code}++\begin{code}+emptyFM = EmptyFM+{-+emptyFM+  = Branch bottom bottom 0 bottom bottom+  where+    bottom = panic "emptyFM"+-}++-- #define EmptyFM (Branch _ _ 0 _ _)++unitFM key elt = Branch key elt 1 emptyFM emptyFM++listToFM = addListToFM emptyFM+++\end{code}++%************************************************************************+%*									*+\subsection{Adding to and deleting from @FiniteMaps@}+%*									*+%************************************************************************++\begin{code}+addToFM fm key elt = addToFM_C (\ old new -> new) fm key elt++addToFM_C combiner EmptyFM key elt = unitFM key elt+addToFM_C combiner (Branch key elt size fm_l fm_r) new_key new_elt++  | new_key < key = mkBalBranch key elt (addToFM_C combiner fm_l new_key new_elt) fm_r+  | new_key > key = mkBalBranch key elt fm_l (addToFM_C combiner fm_r new_key new_elt)+  | otherwise	  = Branch new_key (combiner elt new_elt) size fm_l fm_r+++addListToFM fm key_elt_pairs = addListToFM_C (\ old new -> new) fm key_elt_pairs++addListToFM_C combiner fm key_elt_pairs+  = foldl add fm key_elt_pairs	-- foldl adds from the left+  where+    add fmap (key,elt) = addToFM_C combiner fmap key elt+\end{code}++\begin{code}+delFromFM EmptyFM del_key = emptyFM+delFromFM (Branch key elt size fm_l fm_r) del_key++  | del_key > key+  = mkBalBranch key elt fm_l (delFromFM fm_r del_key)++  | del_key < key+  = mkBalBranch key elt (delFromFM fm_l del_key) fm_r++  | key == del_key+  = glueBal fm_l fm_r+++delListFromFM fm keys = foldl delFromFM fm keys+\end{code}++%************************************************************************+%*									*+\subsection{Combining @FiniteMaps@}+%*									*+%************************************************************************++\begin{code}+plusFM_C combiner EmptyFM fm2 = fm2+plusFM_C combiner fm1 EmptyFM = fm1+plusFM_C combiner fm1 (Branch split_key elt2 _ left right)+  = mkVBalBranch split_key new_elt+		 (plusFM_C combiner lts left)+		 (plusFM_C combiner gts right)+  where+    lts     = splitLT fm1 split_key+    gts     = splitGT fm1 split_key+    new_elt = case lookupFM fm1 split_key of+		Nothing   -> elt2+		Just elt1 -> combiner elt1 elt2++-- It's worth doing plusFM specially, because we don't need+-- to do the lookup in fm1.++plusFM EmptyFM fm2 = fm2+plusFM fm1 EmptyFM = fm1+plusFM fm1 (Branch split_key elt1 _ left right)+  = mkVBalBranch split_key elt1 (plusFM lts left) (plusFM gts right)+  where+    lts     = splitLT fm1 split_key+    gts     = splitGT fm1 split_key++minusFM EmptyFM fm2 = emptyFM+minusFM fm1 EmptyFM = fm1+minusFM fm1 (Branch split_key elt _ left right)+  = glueVBal (minusFM lts left) (minusFM gts right)+	-- The two can be way different, so we need glueVBal+  where+    lts = splitLT fm1 split_key		-- NB gt and lt, so the equal ones+    gts = splitGT fm1 split_key		-- are not in either.++intersectFM fm1 fm2 = intersectFM_C (\ left right -> right) fm1 fm2++intersectFM_C combiner fm1 EmptyFM = emptyFM+intersectFM_C combiner EmptyFM fm2 = emptyFM+intersectFM_C combiner fm1 (Branch split_key elt2 _ left right)++  | isJust maybe_elt1	-- split_elt *is* in intersection+  = mkVBalBranch split_key (combiner elt1 elt2) (intersectFM_C combiner lts left)+						(intersectFM_C combiner gts right)++  | otherwise			-- split_elt is *not* in intersection+  = glueVBal (intersectFM_C combiner lts left) (intersectFM_C combiner gts right)++  where+    lts = splitLT fm1 split_key		-- NB gt and lt, so the equal ones+    gts = splitGT fm1 split_key		-- are not in either.++    maybe_elt1 = lookupFM fm1 split_key+    Just elt1  = maybe_elt1+\end{code}++%************************************************************************+%*									*+\subsection{Mapping, folding, and filtering with @FiniteMaps@}+%*									*+%************************************************************************++\begin{code}+foldFM k z EmptyFM = z+foldFM k z (Branch key elt _ fm_l fm_r)+  = foldFM k (k key elt (foldFM k z fm_r)) fm_l++mapFM f EmptyFM = emptyFM+mapFM f (Branch key elt size fm_l fm_r)+  = Branch key (f key elt) size (mapFM f fm_l) (mapFM f fm_r)++mapMaybeFM f EmptyFM = emptyFM+mapMaybeFM f (Branch key elt _ fm_l fm_r) =+  case f key elt of+    Nothing   -> glueVBal (mapMaybeFM f fm_l) (mapMaybeFM f fm_r)+    Just elt' -> mkVBalBranch key elt' (mapMaybeFM f fm_l) (mapMaybeFM f fm_r)++filterFM p EmptyFM = emptyFM+filterFM p (Branch key elt _ fm_l fm_r)+  | p key elt		-- Keep the item+  = mkVBalBranch key elt (filterFM p fm_l) (filterFM p fm_r)++  | otherwise		-- Drop the item+  = glueVBal (filterFM p fm_l) (filterFM p fm_r)+\end{code}++%************************************************************************+%*									*+\subsection{Interrogating @FiniteMaps@}+%*									*+%************************************************************************++\begin{code}+--{-# INLINE sizeFM #-}+sizeFM EmptyFM		     = 0+sizeFM (Branch _ _ size _ _) =  size++isEmptyFM fm = sizeFM fm == 0++lookupFM EmptyFM key = Nothing+lookupFM (Branch key elt _ fm_l fm_r) key_to_find++  | key_to_find < key = lookupFM fm_l key_to_find+  | key_to_find > key = lookupFM fm_r key_to_find+  | otherwise	  = Just elt+++key `elemFM` fm+  = case (lookupFM fm key) of { Nothing -> False; Just elt -> True }++lookupWithDefaultFM fm deflt key+  = case (lookupFM fm key) of { Nothing -> deflt; Just elt -> elt }+\end{code}++%************************************************************************+%*									*+\subsection{Listifying @FiniteMaps@}+%*									*+%************************************************************************++\begin{code}+fmToList fm = foldFM (\ key elt rest -> (key,elt) : rest) [] fm+keysFM fm   = foldFM (\ key elt rest -> key : rest)       [] fm+eltsFM fm   = foldFM (\ key elt rest -> elt : rest)       [] fm+\end{code}+++%************************************************************************+%*									*+\subsection{The implementation of balancing}+%*									*+%************************************************************************++%************************************************************************+%*									*+\subsubsection{Basic construction of a @FiniteMap@}+%*									*+%************************************************************************++@mkBranch@ simply gets the size component right.  This is the ONLY+(non-trivial) place the Branch object is built, so the ASSERTion+recursively checks consistency.  (The trivial use of Branch is in+@unitFM@.)++\begin{code}+sIZE_RATIO :: Int+sIZE_RATIO = 5++mkBranch :: (Ord key {--}) 		-- Used for the assertion checking only+	 => Int+	 -> key -> elt+	 -> FiniteMap key elt -> FiniteMap key elt+	 -> FiniteMap key elt++mkBranch which key elt fm_l fm_r+  = --{--}++    let+	result = Branch key elt (unbox (1 + left_size + right_size)) fm_l fm_r+    in+--    if sizeFM result <= 8 then+	result+--    else+--	pprTrace ("mkBranch:"++(show which)) (ppr PprDebug result) (+--	result+--	)+  where+    left_ok  = case fm_l of+		EmptyFM		         -> True+		Branch left_key _ _ _ _  -> let+						biggest_left_key = fst (findMax fm_l)+					    in+					    biggest_left_key < key+    right_ok = case fm_r of+		EmptyFM		         -> True+		Branch right_key _ _ _ _ -> let+						smallest_right_key = fst (findMin fm_r)+					    in+					    key < smallest_right_key+    balance_ok = True -- sigh+{- LATER:+    balance_ok+      = -- Both subtrees have one or no elements...+	(left_size + right_size <= 1)+-- NO	      || left_size == 0  -- ???+-- NO	      || right_size == 0 -- ???+    	-- ... or the number of elements in a subtree does not exceed+	-- sIZE_RATIO times the number of elements in the other subtree+      || (left_size  * sIZE_RATIO >= right_size &&+    	  right_size * sIZE_RATIO >= left_size)+-}++    left_size  = sizeFM fm_l+    right_size = sizeFM fm_r+++    unbox :: Int -> Int+    unbox x = x++\end{code}++%************************************************************************+%*									*+\subsubsection{{\em Balanced} construction of a @FiniteMap@}+%*									*+%************************************************************************++@mkBalBranch@ rebalances, assuming that the subtrees aren't too far+out of whack.++\begin{code}+mkBalBranch :: (Ord key {--})+	    => key -> elt+	    -> FiniteMap key elt -> FiniteMap key elt+	    -> FiniteMap key elt++mkBalBranch key elt fm_L fm_R++  | size_l + size_r < 2+  = mkBranch 1{-which-} key elt fm_L fm_R++  | size_r > sIZE_RATIO * size_l	-- Right tree too big+  = case fm_R of+	Branch _ _ _ fm_rl fm_rr+		| sizeFM fm_rl < 2 * sizeFM fm_rr -> single_L fm_L fm_R+		| otherwise	   	          -> double_L fm_L fm_R+	-- Other case impossible++  | size_l > sIZE_RATIO * size_r	-- Left tree too big+  = case fm_L of+	Branch _ _ _ fm_ll fm_lr+		| sizeFM fm_lr < 2 * sizeFM fm_ll -> single_R fm_L fm_R+		| otherwise		          -> double_R fm_L fm_R+	-- Other case impossible++  | otherwise				-- No imbalance+  = mkBranch 2{-which-} key elt fm_L fm_R++  where+    size_l   = sizeFM fm_L+    size_r   = sizeFM fm_R++    single_L fm_l (Branch key_r elt_r _ fm_rl fm_rr)+	= mkBranch 3{-which-} key_r elt_r (mkBranch 4{-which-} key elt fm_l fm_rl) fm_rr++    double_L fm_l (Branch key_r elt_r _ (Branch key_rl elt_rl _ fm_rll fm_rlr) fm_rr)+	= mkBranch 5{-which-} key_rl elt_rl (mkBranch 6{-which-} key   elt   fm_l   fm_rll)+				 (mkBranch 7{-which-} key_r elt_r fm_rlr fm_rr)++    single_R (Branch key_l elt_l _ fm_ll fm_lr) fm_r+	= mkBranch 8{-which-} key_l elt_l fm_ll (mkBranch 9{-which-} key elt fm_lr fm_r)++    double_R (Branch key_l elt_l _ fm_ll (Branch key_lr elt_lr _ fm_lrl fm_lrr)) fm_r+	= mkBranch 10{-which-} key_lr elt_lr (mkBranch 11{-which-} key_l elt_l fm_ll  fm_lrl)+				 (mkBranch 12{-which-} key   elt   fm_lrr fm_r)+\end{code}+++\begin{code}+mkVBalBranch :: (Ord key {--})+	     => key -> elt+	     -> FiniteMap key elt -> FiniteMap key elt+	     -> FiniteMap key elt++-- Assert: in any call to (mkVBalBranch_C comb key elt l r),+--	   (a) all keys in l are < all keys in r+--	   (b) all keys in l are < key+--	   (c) all keys in r are > key++mkVBalBranch key elt EmptyFM fm_r = addToFM fm_r key elt+mkVBalBranch key elt fm_l EmptyFM = addToFM fm_l key elt++mkVBalBranch key elt fm_l@(Branch key_l elt_l _ fm_ll fm_lr)+		     fm_r@(Branch key_r elt_r _ fm_rl fm_rr)+  | sIZE_RATIO * size_l < size_r+  = mkBalBranch key_r elt_r (mkVBalBranch key elt fm_l fm_rl) fm_rr++  | sIZE_RATIO * size_r < size_l+  = mkBalBranch key_l elt_l fm_ll (mkVBalBranch key elt fm_lr fm_r)++  | otherwise+  = mkBranch 13{-which-} key elt fm_l fm_r++  where+    size_l = sizeFM fm_l+    size_r = sizeFM fm_r+\end{code}++%************************************************************************+%*									*+\subsubsection{Gluing two trees together}+%*									*+%************************************************************************++@glueBal@ assumes its two arguments aren't too far out of whack, just+like @mkBalBranch@.  But: all keys in first arg are $<$ all keys in+second.++\begin{code}+glueBal :: (Ord key {--})+	=> FiniteMap key elt -> FiniteMap key elt+	-> FiniteMap key elt++glueBal EmptyFM fm2 = fm2+glueBal fm1 EmptyFM = fm1+glueBal fm1 fm2+	-- The case analysis here (absent in Adams' program) is really to deal+	-- with the case where fm2 is a singleton. Then deleting the minimum means+	-- we pass an empty tree to mkBalBranch, which breaks its invariant.+  | sizeFM fm2 > sizeFM fm1+  = mkBalBranch mid_key2 mid_elt2 fm1 (deleteMin fm2)++  | otherwise+  = mkBalBranch mid_key1 mid_elt1 (deleteMax fm1) fm2+  where+    (mid_key1, mid_elt1) = findMax fm1+    (mid_key2, mid_elt2) = findMin fm2+\end{code}++@glueVBal@ copes with arguments which can be of any size.+But: all keys in first arg are $<$ all keys in second.++\begin{code}+glueVBal :: (Ord key {--})+	 => FiniteMap key elt -> FiniteMap key elt+	 -> FiniteMap key elt++glueVBal EmptyFM fm2 = fm2+glueVBal fm1 EmptyFM = fm1+glueVBal fm_l@(Branch key_l elt_l _ fm_ll fm_lr)+	 fm_r@(Branch key_r elt_r _ fm_rl fm_rr)+  | sIZE_RATIO * size_l < size_r+  = mkBalBranch key_r elt_r (glueVBal fm_l fm_rl) fm_rr++  | sIZE_RATIO * size_r < size_l+  = mkBalBranch key_l elt_l fm_ll (glueVBal fm_lr fm_r)++  | otherwise		-- We now need the same two cases as in glueBal above.+  = glueBal fm_l fm_r+  where+    size_l = sizeFM fm_l+    size_r = sizeFM fm_r+\end{code}++%************************************************************************+%*									*+\subsection{Local utilities}+%*									*+%************************************************************************++\begin{code}+splitLT, splitGT :: (Ord key {--}) => FiniteMap key elt -> key -> FiniteMap key elt++-- splitLT fm split_key  =  fm restricted to keys <  split_key+-- splitGT fm split_key  =  fm restricted to keys >  split_key++splitLT EmptyFM split_key = emptyFM+splitLT (Branch key elt _ fm_l fm_r) split_key++  | split_key < key = splitLT fm_l split_key+  | split_key > key = mkVBalBranch key elt fm_l (splitLT fm_r split_key)+  | otherwise	    = fm_l+++splitGT EmptyFM split_key = emptyFM+splitGT (Branch key elt _ fm_l fm_r) split_key++  | split_key > key = splitGT fm_r split_key+  | split_key < key = mkVBalBranch key elt (splitGT fm_l split_key) fm_r+  | otherwise	    = fm_r+++findMin :: FiniteMap key elt -> (key,elt)+findMin (Branch key elt _ EmptyFM _) = (key,elt)+findMin (Branch key elt _ fm_l    _) = findMin fm_l++deleteMin :: (Ord key {--}) => FiniteMap key elt -> FiniteMap key elt+deleteMin (Branch key elt _ EmptyFM fm_r) = fm_r+deleteMin (Branch key elt _ fm_l    fm_r) = mkBalBranch key elt (deleteMin fm_l) fm_r++findMax :: FiniteMap key elt -> (key,elt)+findMax (Branch key elt _ _ EmptyFM) = (key,elt)+findMax (Branch key elt _ _    fm_r) = findMax fm_r++deleteMax :: (Ord key {--}) => FiniteMap key elt -> FiniteMap key elt+deleteMax (Branch key elt _ fm_l EmptyFM) = fm_l+deleteMax (Branch key elt _ fm_l    fm_r) = mkBalBranch key elt fm_l (deleteMax fm_r)+\end{code}++%************************************************************************+%*									*+\subsection{Output-ery}+%*									*+%************************************************************************++\begin{code}++++instance (Eq key, Eq elt) => Eq (FiniteMap key elt) where+  fm_1 == fm_2 = (sizeFM   fm_1 == sizeFM   fm_2) &&   -- quick test+		 (fmToList fm_1 == fmToList fm_2)++{- NO: not clear what The Right Thing to do is:+instance (Ord key, Ord elt) => Ord (FiniteMap key elt) where+  fm_1 <= fm_2 = (sizeFM   fm_1 <= sizeFM   fm_2) &&   -- quick test+		 (fmToList fm_1 <= fmToList fm_2)+-}++\end{code}++%************************************************************************+%*									*+\subsection{Efficiency pragmas for GHC}+%*									*+%************************************************************************++When the FiniteMap module is used in GHC, we specialise it for+\tr{Uniques}, for dastardly efficiency reasons.++\begin{code}++\end{code}
+ FiniteMap.cabal view
@@ -0,0 +1,14 @@+Name:                FiniteMap+Version:             0.1+Synopsis:            A finite map implementation, derived from the paper: Efficient sets: a balancing act, S. Adams, Journal of functional programming 3(4) Oct 1993, pp553-562+Description:         This is the deprecated Data.FiniteMap library, often useful to get old code to build when you are too lazy to update it.+License:             BSD4+License-file:        LICENSE+Category:            Data+Author:              The University of Glasgow 2001+copyright:           The University of Glasgow 2001+Maintainer:          Pepe Iborra <mnislaih@gmail.com>+Build-Depends:       haskell98, base+exposed-modules:     Data.FiniteMap+buildable:           True+ghc-options:         -O2
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright The University of Glasgow 2001+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * 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.++    * Neither the name of the author(s) nor the names of other+      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+OWNER 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.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain