kure (empty) → 0.2
raw patch · 9 files changed
+602/−0 lines, 9 filesdep +basedep +containerssetup-changed
Dependencies added: base, containers
Files
- LICENSE +25/−0
- Language/KURE.hs +26/−0
- Language/KURE/Combinators.hs +141/−0
- Language/KURE/Rewrite.hs +46/−0
- Language/KURE/RewriteMonad.hs +147/−0
- Language/KURE/Term.hs +108/−0
- Language/KURE/Translate.hs +63/−0
- Setup.hs +2/−0
- kure.cabal +44/−0
+ LICENSE view
@@ -0,0 +1,25 @@+Copyright (c) 2006-2008 Andy Gill+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. The names of the authors may not be used to endorse or promote products+ derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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.+
+ Language/KURE.hs view
@@ -0,0 +1,26 @@+-- |+-- Module: Language.KURE+-- Copyright: (c) 2006-2008 Andy Gill+-- License: BSD3+--+-- Maintainer: Andy Gill <andygill@ku.edu>+-- Stability: unstable+-- Portability: ghc+--+-- This is the main import module for KURE, which exports all the major components.+--+--++module Language.KURE + ( module Language.KURE.RewriteMonad+ , module Language.KURE.Translate+ , module Language.KURE.Rewrite+ , module Language.KURE.Combinators+ , module Language.KURE.Term+ ) where++import Language.KURE.RewriteMonad+import Language.KURE.Translate+import Language.KURE.Rewrite+import Language.KURE.Combinators+import Language.KURE.Term
+ Language/KURE/Combinators.hs view
@@ -0,0 +1,141 @@+-- |+-- Module: Language.KURE.Combinators +-- Copyright: (c) 2006-2008 Andy Gill+-- License: BSD3+--+-- Maintainer: Andy Gill <andygill@ku.edu>+-- Stability: unstable+-- Portability: ghc+--+-- This module contains various combinators that use 'Translate' and 'Rewrite'. The convension is that+-- 'Translate' based combinators end with @T@, and 'Rewrite' based combinators end with @R@. Of course,+-- because 'Rewrite' is a type synomim of 'Translate', the 'Rewrite' functions also operate with on 'Translate',+-- and the 'Translate' functions operate with 'Rewrite'. ++module Language.KURE.Combinators + ( -- * 'Translate' combinators+ (<+)+ , (>->)+ , failT+ , (?)+ , readerT+ , getDecsT+ , mapDecsT+ , pureT+ , constT+ , concatT+ , -- * 'Rewrite' combinators+ (.+)+ , (!->)+ , tryR+ , changedR+ , repeatR+ , acceptR+ , idR+ , failR+ ) where + +import Language.KURE.RewriteMonad +import Language.KURE.Translate +import Language.KURE.Rewrite +import Data.Monoid++infixl 3 <+, >->, .+, !->+infixr 3 ?++-- Note: We use < for catching fail, . for catching id.++--------------------------------------------------------------------------------+-- The Translate combinators.++-- | like a catch, '<+' does the first translate , and if it fails, then does the second translate. +(<+) :: (Monoid dec, Monad m) => Translate m dec a b -> Translate m dec a b -> Translate m dec a b+(<+) rr1 rr2 = translate $ \ e -> transparently $ apply rr1 e `catchM` (\ _ -> apply rr2 e)++-- | like a @;@ If the first translate succeeds, then do to the second translate after the first translate.+(>->) :: (Monoid dec, Monad m) => Translate m dec a b -> Translate m dec b c -> Translate m dec a c+(>->) rr1 rr2 = translate $ \ e -> transparently $ chainM (apply rr1 e) ( \ _i e2 -> apply rr2 e2)++-- | failing translation.+failT :: (Monad m, Monoid dec) => String -> Translate m dec a b+failT msg = translate $ \ _ -> failM msg++-- | Guarded translate.+(?) :: (Monoid dec, Monad m) => Bool -> Translate m dec a b -> Translate m dec a b+(?) False _rr = failT "(False ?)"+(?) True rr = rr++-- | look at the argument for the translation before choosing which translation to perform. +readerT :: (Monoid dec, Monad m) => (a -> Translate m dec a b) -> Translate m dec a b+readerT fn = translate $ \ expA -> transparently $ apply (fn expA) expA++-- | look at the @dec@ before choosing which translation to do.+getDecsT :: (Monad m, Monoid dec) => (dec -> Translate m dec a b) -> Translate m dec a b+getDecsT f = translate $ \ e -> transparently $+ do dec <- getDecsM + apply (f dec) e++-- | change the @dec@'s for a scoped translation.+mapDecsT :: (Monoid dec,Monad m) => (dec -> dec) -> Translate m dec a r -> Translate m dec a r+mapDecsT f_env rr = translate $ \ e -> mapDecsM f_env (apply rr e)++-- | 'pureT' promotes a function into an unfailable, non-identity 'Translate'.+pureT :: (Monad m,Monoid dec) => (a -> b) -> Translate m dec a b+pureT f = translate $ \ a -> return (f a)++-- | 'constT' always translates into an unfailable 'Translate' that returns the first argument.+constT :: (Monad m,Monoid dec) => b -> Translate m dec a b+constT = pureT . const++-- | 'concatT' composes a list of 'Translate' into a single 'Translate' which 'mconcat's its result.+concatT :: (Monad m,Monoid dec,Monoid r) => [Translate m dec a r] -> Translate m dec a r+concatT ts = translate $ \ e -> do+ rs <- sequence [ apply t e | t <- ts ]+ return (mconcat rs)+--------------------------------------------------------------------------------+-- The 'Rewrite' combinators.++-- | if the first rewrite is an identity, then do the second rewrite.+(.+) :: (Monoid dec, Monad m) => Rewrite m dec a -> Rewrite m dec a -> Rewrite m dec a+(.+) a b = a `wasId` (\ i -> if i then b else idR)++-- | if the first rewrite was /not/ an identity, then also do the second rewrite.+(!->) :: (Monoid dec, Monad m) => Rewrite m dec a -> Rewrite m dec a -> Rewrite m dec a +(!->) a b = a `wasId` (\ i -> if i then idR else b)++-- | catch a failing 'Rewrite', making it into an identity.+tryR :: (Monoid dec, Monad m) => Rewrite m dec a -> Rewrite m dec a+tryR s = s <+ idR++-- | if this is an identity rewrite, make it fail. To succeed, something must have changed.+changedR :: (Monoid dec,Monad m) => Rewrite m dec a -> Rewrite m dec a+changedR rr = rr .+ failR "unchanged"++-- | repeat a rewrite until it fails, then return the result before the failure.+repeatR :: (Monoid dec, Monad m) => Rewrite m dec a -> Rewrite m dec a+repeatR s = tryR (s >-> repeatR s) ++-- | look at the argument to a rewrite, and choose to be either a failure of trivial success.+acceptR :: (Monoid dec, Monad m) => (a -> Bool) -> Rewrite m dec a+acceptR fn = translate $ \ expA -> transparently $+ if fn expA + then return expA+ else fail "accept failed"+++-- | identity rewrite.+idR :: (Monad m, Monoid dec) => Rewrite m dec exp+idR = rewrite $ \ e -> transparently $ return e++-- | failing rewrite.+failR :: (Monad m, Monoid dec) => String -> Rewrite m dec a+failR = failT+++--------------------------------------------------------------------------------+-- internal to this module.+wasId :: (Monoid dec, Monad m) => Rewrite m dec a -> (Bool -> Rewrite m dec a) -> Rewrite m dec a+wasId rr fn = translate $ \ e -> transparently $+ chainM (apply rr e)+ (\ i e' -> apply (fn i) e')+
+ Language/KURE/Rewrite.hs view
@@ -0,0 +1,46 @@+-- |+-- Module: Language.KURE.Rewrite +-- Copyright: (c) 2006-2008 Andy Gill+-- License: BSD3+--+-- Maintainer: Andy Gill <andygill@ku.edu>+-- Stability: unstable+-- Portability: ghc+--+-- 'Rewrite' is a synonoym for a 'Translate' with the same source and target type.+-- This module contains the defintion of Rewrite, and some aliases for some translate functions that use +-- Rewrite rather than Translate.++module Language.KURE.Rewrite + ( Rewrite+ , rewrite+ , runRewrite+ ) where++import Language.KURE.RewriteMonad+import Language.KURE.Translate+import Data.Monoid++-- | A 'Rewrite' is a 'Translate' that shares the same source and target type. Literally, +-- a 'Rewrite' provides the details about how to /re-write/ a specific type.++type Rewrite m dec exp = Translate m dec exp exp++-- | 'rewrite' is our primitive way of building a Rewrite,+-- where if the rewrite is successful it is automatically marked as a non-identity rewrite. +--+-- @rewrite $ \\ _ e -> return e@ /is not/ an identity rewrite. ++rewrite :: (Monoid dec, Monad m) => (exp1 -> RewriteM m dec exp1) -> Rewrite m dec exp1+rewrite = translate++-- | 'runRewrite' executes the rewrite, returning either a failure message,+-- or a success and the new parts of the environment.+++runRewrite :: (Monoid dec,Monad m) + => Rewrite m dec exp+ -> dec + -> exp + -> m (Either String (exp,dec))+runRewrite = runTranslate
+ Language/KURE/RewriteMonad.hs view
@@ -0,0 +1,147 @@+-- |+-- Module: Language.KURE.RewriteMonad +-- Copyright: (c) 2006-2008 Andy Gill+-- License: BSD3+--+-- Maintainer: Andy Gill <andygill@ku.edu>+-- Stability: unstable+-- Portability: ghc+--+-- This is the definition of the monad inside KURE.++module Language.KURE.RewriteMonad + ( RewriteM -- abstract+ , RewriteStatusM(..)+ , runRewriteM+ , failM+ , catchM+ , chainM+ , liftQ+ , markM+ , transparently+ , getDecsM+ , mapDecsM+ ) where +++import Control.Monad+import Data.Monoid++------------------------------------------------------------------------------++data RewriteM m dec exp = + RewriteM { -- | 'runRewriteM' runs the 'RewriteM' monad, returning a status.+ runRewriteM :: dec -> m (RewriteStatusM dec exp) + }++data IdStatus = EmptyId | IsId | NotId++instance Monoid IdStatus where+ mempty = EmptyId+ + mappend EmptyId y = y+ mappend x EmptyId = x+ mappend IsId IsId = IsId+ mappend _ _ = NotId++data RewriteStatusM dec exp+ = RewriteReturnM exp !(Maybe dec) !IdStatus -- ^ a regular success+ | RewriteFailureM String -- ^ a real failure+-- | RewriteIdM exp -- ^ identity marker on a value+++-- TWO possible ways of thinking about rewriting:++-- C1 (e1) => C2 (C1 (e2)) => C3 (C2 (C1 (e3))) -- matches the *writer* like status+-- C1 (e1) => C1 (C2 (e2)) => C1 (C2 (C3 (e3))) -- will require mergeing??++instance (Monoid dec,Monad m) => Monad (RewriteM m dec) where+ return e = RewriteM $ \ _ -> return $ RewriteReturnM e Nothing EmptyId+ (RewriteM m) >>= k = RewriteM $ \ dec -> do+ r <- m dec+ case r of+ RewriteReturnM r1 ds ids -> do+ r2 <- runRewriteM (k r1) dec+ return $ case r2 of+ RewriteReturnM e' ds' ids' -> RewriteReturnM e' (ds' `mappend` ds) (ids' `mappend` ids)+ RewriteFailureM msg -> RewriteFailureM msg+ RewriteFailureM msg -> return $ RewriteFailureM msg++ fail msg = RewriteM $ \ _ -> return $ RewriteFailureM msg++instance (Monoid dec,Monad m) => Functor (RewriteM m dec) where+ fmap f m = liftM f m++-- | 'liftQ' lets you tunnel into the inner monad, because 'RewriteM' is actually monad transformer.+liftQ :: (Monad m,Monoid dec) => m a -> RewriteM m dec a +liftQ m = RewriteM $ \ _ -> do r <- m+ return $ RewriteReturnM r mempty mempty++-- | 'failM' is our basic failure, with a String message.+failM :: (Monad m, Monoid dec) => String -> RewriteM m dec a+failM msg = RewriteM $ \ _ -> return $ RewriteFailureM msg++-- | 'catchM' catches failures, and tries a second monadic computation.+catchM :: (Monad m) => RewriteM m dec a -> (String -> RewriteM m dec a) -> RewriteM m dec a+catchM (RewriteM m1) m2 = RewriteM $ \ dec -> do+ r <- m1 dec+ case r of+ RewriteReturnM {} -> return r + RewriteFailureM msg -> runRewriteM (m2 msg) dec+ + +-- | 'chainM' executes the first argument then the second, much like '>>=',+-- except that the second computation can see if the first computation was an identity or not.+-- Used to spot when a rewrite succeeded, but was the identity.++chainM :: (Monoid dec,Monad m) + => (RewriteM m dec b) + -> (Bool -> b -> RewriteM m dec c)+ -> RewriteM m dec c+chainM m k = RewriteM $ \ dec -> do+ r <- runRewriteM m dec+ case r of+ RewriteReturnM a ds ids -> + do r2 <- runRewriteM (k (isId ids) a) (case ds of+ Nothing -> dec+ Just ds2 -> ds2 `mappend` dec)+ case r2 of+ RewriteReturnM a' ds' ids' ->+ return $ RewriteReturnM a' (ds' `mappend` ds) (ids' `mappend` ids)+ RewriteFailureM msg -> return $ RewriteFailureM msg+ RewriteFailureM msg -> return $ RewriteFailureM msg -- and still fail + where+ isId NotId = False+ isId _ = True+ +-- | 'markM' is used to mark a monadic rewrite as a non-identity,+-- unless the congruence flag is set.+markM :: (Monad m) => RewriteM m dec a -> RewriteM m dec a+markM (RewriteM m) = RewriteM $ \ dec -> do+ r <- m dec+ case r of+ RewriteReturnM a ds EmptyId -> return $ RewriteReturnM a ds NotId+ RewriteReturnM a ds IsId -> return $ RewriteReturnM a ds EmptyId+ RewriteReturnM a ds ids -> return $ RewriteReturnM a ds ids+ RewriteFailureM msg -> return $ RewriteFailureM msg+ +-- | 'transparently' sets the congruence flag, such that if the+-- monadic action was identity preserving, then a 'markM' does+-- not set the non-indentity flag.+ +transparently :: (Monad m) => RewriteM m dec a -> RewriteM m dec a+transparently (RewriteM m) = RewriteM $ \ dec -> do+ r <- m dec+ case r of+ RewriteReturnM a ds EmptyId -> return $ RewriteReturnM a ds IsId+ RewriteReturnM a ds ids -> return $ RewriteReturnM a ds ids+ RewriteFailureM msg -> return $ RewriteFailureM msg+++-- | 'getDecsM' reads the local environment+getDecsM :: (Monad m, Monoid dec) => RewriteM m dec dec+getDecsM = RewriteM $ \ dec -> return $ RewriteReturnM dec mempty mempty++-- | 'mapDecs" changes the local environment, inside a local monadic invocation.+mapDecsM :: (Monad m, Monoid dec) => (dec -> dec) -> RewriteM m dec a -> RewriteM m dec a+mapDecsM fn (RewriteM m) = RewriteM $ \ dec -> m (fn dec)
+ Language/KURE/Term.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses #-}++-- | This module supports the generic walking of 'Term's. +--+-- The key idea here is that for each type of expression (@exp@), +-- we have a sum of all the interesting children types (@Generic exp@).+-- There is always a type that its own 'Generic', which is used for the +-- deeper syntax tree walks.++module Language.KURE.Term + ( Term(..)+ , Walker(..)+ , extractR+ , promoteR+ , extractU+ , topdownR+ , bottomupR + , alltdR + , downupR + , innermostR + , foldU + ) where+ +import Language.KURE.RewriteMonad as M +import Language.KURE.Translate +import Language.KURE.Rewrite+import Language.KURE.Combinators -- perhaps++import Control.Monad+import Data.Monoid++-- | 'Term's are things that syntax are built from.+class Term exp where+ -- | 'Generic' is a sum of all the interesting sub-types, transitively, of @exp@. + -- We use @Generic e ~ e@ to signify that something is its own Generic.+ -- Simple expression types might be their own sole 'Generic', more complex examples+ -- will have a new datatype for the 'Generic', which will also be an instance of class 'Term'.+ type Generic exp++ -- | 'project' projects into a 'Generic' exp, to get the exp inside, or fail.+ -- TODO: rename as select+ select :: Generic exp -> Maybe exp++ -- | 'inject' injects an exp into a 'Generic' exp.+ inject :: exp -> Generic exp+++-- | 'Walker' captures how we walk over @exp@, using a specific @m@ and @dec@.+class (Monoid dec,Monad m,Term exp) => Walker m dec exp where+ -- | 'allR' applies 'Generic' rewrites to all the interesting children of this node.+ allR :: Rewrite m dec (Generic exp) -> Rewrite m dec exp+ -- | 'allU' applied a 'Generic' Translation to a common, 'Monoid'al result, to all the interesting children of this node.+ crushU :: (Monoid result) => Translate m dec (Generic exp) result -> Translate m dec exp result++------------------------------------------------------------------------------++-- | 'extract' converts a 'Rewrite' over a 'Generic' into a rewrite over a specific expression type. ++extractR :: (Monad m, Term exp, Monoid dec) => Rewrite m dec (Generic exp) -> Rewrite m dec exp -- at *this* type+extractR rr = rewrite $ \ e -> transparently $ do+ e' <- apply rr (inject e)+ case select e' of+ Nothing -> fail "extractR"+ Just r -> return r+ +-- | 'promote' promotes a 'Rewrite' into a 'Generic' 'Rewrite'; other types inside Generic cause failure.+-- 'try' can be used to convert a failure-by-default promotion into a 'id-by-default' promotion.++promoteR :: (Monad m, Term exp, Monoid dec) => Rewrite m dec exp -> Rewrite m dec (Generic exp)+promoteR rr = rewrite $ \ e -> transparently $ do+ case select e of+ Nothing -> fail "promoteR"+ Just e' -> do+ r <- apply rr e'+ return (inject r)++-- | 'accept' ++extractU :: (Monad m, Term exp, Monoid dec) => Translate m dec (Generic exp) r -> Translate m dec exp r+extractU rr = translate $ \ e -> transparently $ apply rr (inject e)++-------------------------------------------------------------------------------++-- apply a rewrite in a top down manner.+topdownR :: (e ~ Generic e, Walker m dec e) => Rewrite m dec e -> Rewrite m dec e+topdownR s = s >-> allR (topdownR s)++-- apply a rewrite in a bottom up manner.+bottomupR :: (e ~ Generic e, Walker m dec e) => Rewrite m dec e -> Rewrite m dec e+bottomupR s = allR (bottomupR s) >-> s++-- apply a rewrite in a top down manner, prunning at successful rewrites.+alltdR :: (e ~ Generic e, Walker m dec e) => Rewrite m dec e -> Rewrite m dec e+alltdR s = s <+ allR (alltdR s)++-- apply a rewrite twice, in a topdown and bottom up way, using one single tree traversal.+downupR :: (e ~ Generic e, Walker m dec e) => Rewrite m dec e -> Rewrite m dec e+downupR s = s >-> allR (downupR s) >-> s++-- a fixed point traveral, starting with the innermost term.+innermostR :: (e ~ Generic e, Walker m dec e) => Rewrite m dec e -> Rewrite m dec e+innermostR s = bottomupR (tryR (s >-> innermostR s)) ++-- fold a tree using a single translation for each node.+foldU :: (e ~ Generic e, Walker m dec e, Monoid r) => Translate m dec e r -> Translate m dec e r+foldU s = concatT [ s, crushU (foldU s) ]++-------------------------------------------------------------------------------
+ Language/KURE/Translate.hs view
@@ -0,0 +1,63 @@+-- |+-- Module: Language.KURE.Translate +-- Copyright: (c) 2006-2008 Andy Gill+-- License: BSD3+--+-- Maintainer: Andy Gill <andygill@ku.edu>+-- Stability: unstable+-- Portability: ghc+--+-- 'Translate' is the main abstraction inside KURE, and represents a rewriting from a source to a target+-- of a possibly different type.+--+-- Rewrite (defined in 'Language.KURE.Rewrite') is a synonoym for a 'Translate' with the same source and target type.++module Language.KURE.Translate + ( Translate+ , apply+ , runTranslate+ , translate+ ) where+ +import Control.Monad+import Data.Monoid++import Language.KURE.RewriteMonad++-- | 'Translate' is a translation or strategy that translates between @exp1@ and @exp2@, with the posiblity of failure,+-- and remembers identity translations.++newtype Translate m dec exp1 exp2 =+ Translate ( exp1 -> RewriteM m dec exp2 )++-- | 'apply' directly applies a 'Translate' value to an argument.+apply :: (Monoid dec, Monad m) => Translate m dec exp1 exp2 -> exp1 -> RewriteM m dec exp2+apply (Translate t) exp1 = t exp1 +++-- | 'translate' is the standard way of building a 'Translate', where if the translation is successful it +-- is automatically marked as a non-identity translation. +--+-- Note: @translate $ \ _ e -> return e@ /is not/ an identity rewrite, but a succesful rewrite that+-- returns its provided argument. ++translate :: (Monoid dec, Monad m) => (exp1 -> RewriteM m dec exp2) -> Translate m dec exp1 exp2+translate f = Translate $ \ e -> markM $ f e+++-- | 'runTranslate' executes the translation, returning either a failure message,+-- or a success and the new parts of the environment.++runTranslate :: (Monoid dec,Monad m) + => Translate m dec exp res+ -> dec + -> exp + -> m (Either String (res,dec))+runTranslate rr dec e = do+ res <- runRewriteM (apply rr e) dec+ case res of+ RewriteReturnM exp' Nothing _ -> return (Right (exp',mempty))+ RewriteReturnM exp' (Just ds) _ -> return (Right (exp',ds))+ RewriteFailureM msg -> return (Left msg)++
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ kure.cabal view
@@ -0,0 +1,44 @@+Name: kure+Version: 0.2+Synopsis: Combinators for Strategic Programming+Description: KURE is a DSL for building rewriting DSLs.+ KURE shares combinator names and concepts with Stratego, but unlike Stratego, KURE is strongly typed.+ KURE is similar to Strafunski, but has a lightweight generic traversal mechanism using type families+ rather than SYB,+ and the KURE combinators are parameterized to provide the ability to have context sensitive rewrites.++Category: Language+License: BSD3+License-file: LICENSE+Author: Andy Gill+Maintainer: Andy Gill <andygill@ku.edu>+Copyright: (c) 2006-2008 Andy Gill+Homepage: http://ittc.ku.edu/~andygill/kure.php+Build-Depends: base+Stability: alpha++build-type: Simple+Cabal-Version: >= 1.6+++Library+ Build-Depends: base, containers + Exposed-modules:+ Language.KURE,+ Language.KURE.RewriteMonad, + Language.KURE.Translate,+ Language.KURE.Rewrite,+ Language.KURE.Combinators,+ Language.KURE.Term++ Ghc-Options: -Wall+++--Executable test1+-- Ghc-Options: -fhpc+-- Main-Is: Test.hs+-- Hs-Source-Dirs: ., test+-- buildable: True+++