packages feed

arrowp-qq 0.1.1 → 0.2

raw patch · 28 files changed

+1639/−2485 lines, 28 filesdep +Hoeddep +NoHoeddep +arrowp-qqdep −haskell-srcdep ~basedep ~template-haskellnew-component:exe:arrowp-extPVP ok

version bump matches the API change (PVP)

Dependencies added: Hoed, NoHoed, arrowp-qq, arrows, data-default, haskell-src-exts, haskell-src-exts-observe, haskell-src-exts-util, haskell-src-meta, syb, uniplate

Dependencies removed: haskell-src

Dependency ranges changed: base, template-haskell

API changes (from Hackage documentation)

- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsAlt Language.Haskell.TH.Syntax.Match
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsDecl Language.Haskell.TH.Syntax.Dec
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsExp Language.Haskell.TH.Syntax.Exp
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsFieldUpdate Language.Haskell.TH.Syntax.FieldExp
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsGuardedAlt (Language.Haskell.TH.Syntax.Guard, Language.Haskell.TH.Syntax.Exp)
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsGuardedAlts Language.Haskell.TH.Syntax.Body
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsGuardedRhs (Language.Haskell.TH.Syntax.Guard, Language.Haskell.TH.Syntax.Exp)
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsLiteral Language.Haskell.TH.Syntax.Lit
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsMatch Language.Haskell.TH.Syntax.Clause
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsName [GHC.Types.Char]
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsPat Language.Haskell.TH.Syntax.Pat
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsPatField Language.Haskell.TH.Syntax.FieldPat
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsQName Language.Haskell.TH.Syntax.Name
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsQOp Language.Haskell.TH.Syntax.Exp
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsRhs Language.Haskell.TH.Syntax.Body
- Control.Arrow.QuasiQuoter: instance Control.Arrow.QuasiQuoter.Translate Language.Haskell.Syntax.HsStmt Language.Haskell.TH.Syntax.Stmt
- Control.Arrow.QuasiQuoter: parseModuleWithMode :: ParseMode -> String -> ParseResult HsModule
+ Control.Arrow.Notation: translateExp :: Exp SrcSpanInfo -> Exp SrcSpanInfo
+ Control.Arrow.Notation: translateModule :: Module SrcSpanInfo -> Module SrcSpanInfo

Files

− README
@@ -1,15 +0,0 @@-A prototype quasiquoter for arrow notation packaged by Jose Iborra,-based on the arrowp preprocessor developed by Ross Paterson <ross@soi.city.ac.uk>.--Note that recent versions of GHC support this notation directly, and-give better error messages to boot. But the translation produced by GHC-is in some cases not as good as it could be.--RUNNING THE ARROW QUASI QUOTER---addA :: Arrow a => a b Int -> a b Int -> a b Int-addA f g = [proc| x -> do-		y <- f -< x-		z <- g -< x-		returnA -< y + z |]
+ README.md view
@@ -0,0 +1,101 @@+[![Hackage](https://img.shields.io/hackage/v/arrowp-qq.svg)](https://hackage.haskell.org/package/arrowp-qq)+[![Stackage Nightly](http://stackage.org/package/arrowp-qq/badge/nightly)](http://stackage.org/nightly/package/arrowp-qq)+[![Travis Build Status](https://travis-ci.org/pepeiborra/arrowp-qq.svg)](https://travis-ci.org/pepeiborra/arrowp-qq)++Arrowp-qq+==========+A preprocessor for arrow notation packaged by Jose Iborra,+based on the arrowp preprocessor developed by Ross Paterson <ross@soi.city.ac.uk>.++Notable features include support for GHC Haskell syntax and a+quasiquoter that can be used instead of the preprocessor.++Note that recent versions of GHC support this notation directly, and+give better error messages to boot. But the translation produced by GHC+is in some cases not as good as it could be.++Status+------++The parser cannot handle banana brackets for+control operators in arrow notation (the **proc** keyword in the original paper), +due to a +[limitation](https://github.com/haskell-suite/haskell-src-exts/issues/45) +in haskell-src-exts. In order to use banana brackets, the recommendation+is to fall back to the GHC Arrows parser. ++Support for GHC Haskell notation inside arrow blocks is not complete, e.g.+multi-way-if and lambda case are unlikely to work as expected. If you run into +one of these, please open an issue or vote for an existing one, as I plan to extend+the support on demand.++Using the `proc` quasi quoter+---------------------------++```+addA :: Arrow a => a b Int -> a b Int -> a b Int+addA f g = [proc| x -> do+		y <- f -< x+		z <- g -< x+		returnA -< y + z |]+```++Using the **arrowp-ext** preprocessor+---------------------------------++```+{-# OPTIONS -F -pgmF arrowp-ext #-}+```++Comparison with **arrowp**+-----------------------+**arrowp-qq** extends the original **arrowp** in three dimensions:+1. It replaces the `haskell-src` based parser with one based on `haskell-src-exts`, which handles most of GHC 8.0.2 Haskell syntax.+2. It provides not only a preprocessor but also a quasiquoter, which is a better option in certain cases.+3. It extends the desugaring to handle static conditional expressions (currently only if-then-else). Example:+```+proc inputs -> do+  results <- processor -< inputs+  if outputResultsArg+    then outputSink -< results+    else returnA -< ()+  returnA -< results+```+The standard **arrowp** (and GHC) desugaring for this code is:+```+  = ((processor >>> arr (\ results -> (results, results))) >>>+       (first+          (arr+             (\ results -> if outputResultsArg then Left results else Right ())+             >>> (outputSink ||| returnA))+          >>> arr (\ (_, results) -> results)))+```+This requires an `ArrowChoice`, but there is a more efficient desugaring which +performs the choice at compile time and thus an `Arrow` suffices:+```+((processor >>> arr (\ results -> (results, results))) >>>+       (first+          (if outputResultsArg then outputSink else arr (\ results -> ()))+          >>> arr (\ (_, results) -> results)))+```++Comparison with **GHC**+-----------------------+The GHC desugarer does not do a very good job of minimizing the number of+`first` calls inserted. In certain `Arrow` instances, this can have a material effect+on performance. Example:+```+trivial = proc inputs -> do+   chunked <- chunk -< inputs+   results <- process -< chunked+   returnA -< results+```+This code ought to desugar to a chain of arrows, and indeed, both arrowp and+arrowp-qq desugar this to:+```+trivial = chunk >>> process+```+However GHC will produce (approximately) the following code:+```+  arr(\inputs -> (inputs,inputs)) >>> first chunk >>> first process >>> arr fst+```
+ app/Main.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE RecordWildCards #-}+module Main where++import           Control.Arrow.Notation+import           Data.List+import           Debug.Hoed.Pure+import           Language.Haskell.Exts+import           System.Environment+import           System.Exit+import           System.IO+import           Text.Printf++usage :: String -> String+usage progName = unlines [+  "usage: " ++ progName +++  " [FILENAME] [SOURCE] [DEST]",+  "Read arrow notation from SOURCE (derived from FILENAME) and write",+  "standard Haskell to DEST.",+  "If no FILENAME, use SOURCE as the original name.",+  "If no DEST or if DEST is `-', write to standard output.",+  "If no SOURCE or if SOURCE is `-', read standard input."+  ]++main :: IO ()+main = runO $ do+  args <- getArgs+  progName <- getProgName+  (orig, inp, out) <- case args of+    ["--help"] -> do+      putStrLn $ usage progName+      exitSuccess+    []     -> return ("input",Nothing,Nothing)+    [i]    -> return (i, Just i, Nothing)+    [i,o]  -> return (i, Just i, Just o)+    [orig,i,o] -> return (orig, Just i, Just o)+    _ -> do+      putStrLn $ usage progName+      error "Unrecognized set of command line arguments"+  hIn  <- maybe (return stdin)  (`openFile` ReadMode) inp+  hOut <- maybe (return stdout) (`openFile` WriteMode) out+  contents <- hGetContents hIn+  case parseFileContentsWithExts defaultExtensions contents of+        ParseFailed SrcLoc{..} err -> do+          printf "Parse error at %s:%d:%d: %s" orig srcLine srcColumn err+          exitFailure+        ParseOk x -> do+          let x' = translateModule x+          hPutStr hOut $ prettyPrintWithMode defaultMode{linePragmas=True} x'+          hClose hOut++defaultExtensions :: [Extension]+defaultExtensions = [e | e@EnableExtension{} <- knownExtensions] \\ map EnableExtension badExtensions++badExtensions :: [KnownExtension]+badExtensions =+    [TransformListComp -- steals the group keyword+    ,XmlSyntax, RegularPatterns -- steals a-b+    ,UnboxedTuples -- breaks (#) lens operator+    ,QuasiQuotes -- breaks [x| ...], making whitespace free list comps break+    ,DoRec, RecursiveDo -- breaks rec+    ,TypeApplications -- HSE fails on @ patterns+    ]
arrowp-qq.cabal view
@@ -1,24 +1,100 @@ Name:           arrowp-qq-Version:        0.1.1+Version:        0.2 Cabal-Version:  >= 1.20 Build-Type:     Simple License:        GPL License-File:   LICENCE Author:         Jose Iborra <pepeiborra@gmail.com> Maintainer:     Jose Iborra <pepeiborra@gmail.com>-Homepage:       http://www.haskell.org/arrows/+Homepage:       https://github.com/pepeiborra/arrowp Category:       Development-Synopsis:       quasiquoter translating arrow notation into Haskell 98-Description:    A quasiquoter built on top of the arrowp package.-Extra-Source-Files: README+Synopsis:       A preprocessor and quasiquoter for translating arrow notation+Description:    A suite of preprocessor and quasiquoter to desugar arrow notation built on top of Ross Paterson's arrowp and the venerable haskell-src-exts.+Extra-Source-Files: README.md +Flag Debug+  Description:         Enabled Hoed algorithmic debugging+  Default:             False+  Manual:              True++Flag TestExamples+  Description:         Build the examples using the preprocessor and quasiquoter+  Default: False+  Manual: True               ++Source-Repository head+    Type: git +    Location: http://github.com/pepeiborra/arrowp+ Library-    Exposed-Modules:     Control.Arrow.QuasiQuoter-    Build-Depends: base < 5, array, containers, haskell-src, template-haskell < 2.13, transformers+    Exposed-Modules:     +                         Control.Arrow.Notation,+                         Control.Arrow.QuasiQuoter+    Build-Depends: base < 5,+                   array,+                   containers,+                   data-default,+                   haskell-src-exts,+                   haskell-src-exts-util,+                   haskell-src-meta,+                   syb,+                   template-haskell < 2.13, +                   transformers,+                   uniplate+    if flag(Debug)+       Build-Depends:       Hoed, haskell-src-exts-observe+       cpp-options:         -DDEBUG+    else+       Build-Depends:       NoHoed+     Hs-Source-Dirs: src-    Other-Modules:  ArrCode ArrSyn Lexer Parser Parser State Utils+    Other-Modules:  ArrCode ArrSyn Utils     Default-Language:    Haskell2010 -Source-Repository head-    Type: darcs-    Location: http://github.com/pepeiborra/arrowp+executable arrowp-ext+  buildable: True+  main-is: Main.hs+  hs-source-dirs:+      app+  build-depends:+                base >= 4.7 && < 5, +                arrowp-qq,+                haskell-src-exts+  if flag(Debug)+      Build-Depends:       Hoed+      cpp-options:         -DDEBUG+  else+      Build-Depends:       NoHoed++  default-language: Haskell2010++test-suite examples+  if flag(TestExamples)+     buildable: True+  else+     buildable:  False+  type:                exitcode-stdio-1.0+  hs-source-dirs:+                 examples,+                 examples/cgi,+                 examples/circuits,+                 examples/Parser,+                 examples/powertrees,+                 examples/small+  main-is:             Main.hs+  other-modules:       +                       Parser,+                       ExprParser,+                       BackStateArrow,+                       Conditional,+                       ListOps,+                       Egs,+                       Eval,+                       Eval1,+                       Lift,+                       ListOps,+                       TH.TH,+                       TH.While,+                       TH.BackStateArrow+  build-depends:+    base, arrows, arrowp-qq, template-haskell
+ examples/Conditional.hs view
@@ -0,0 +1,21 @@+{- LANGUAGE Arrows -}+{-# OPTIONS -F -pgmF arrowp-ext #-}++module Conditional where++import           Control.Arrow++-- An Arrow command for use with banana brackets?+static :: Arrow a => Bool -> a b c -> a b d -> a (c,d) c -> a b c+static use abc abd adc = proc b -> do+  c <- abc -< b+  res <- if use -- :: a (b,c) c+     then do -- :: a (b,c) c+       d <- abd -< b+       adc -< (c,d)+     else returnA -< c -- :: a (b,c) c+  returnA -< res++simple :: Bool -> a b c -> a b c+simple use abc = proc b -> do+  if use then abc -< b else abc -< b
+ examples/Main.hs view
@@ -0,0 +1,20 @@+module Main where++import           BackstateArrow    ()+import           CGI               ()+-- import           Circuits          () -- Uses banana brackets+import           Conditional       ()+import           Egs               ()+import           Eval              ()+import           Eval1             ()+import           ExprParser        ()+import           Hom               ()+import           Lift              ()+import           ListOps           ()+import           TH.TH             ()+import           TH.BackstateArrow ()+import           TH.While          ()+++main :: IO ()+main = return ()
+ examples/Parser/ExprParser.lhs view
@@ -0,0 +1,91 @@+> {-# OPTIONS -F -pgmF arrowp-ext #-}+> module ExprParser where++> import Data.Char++> import Control.Arrow+> import Control.Arrow.Transformer.Error++> import Parser++Expressions++> data ESym = LPar | RPar | Plus | Minus | Mult | Div | Number | Unknown | EOF+>	deriving (Show, Eq, Ord)++> instance Symbol ESym where+>	eof = EOF++> type ExprParser = Parser ESym String (->)+> type ExprSym = Sym ESym String++The grammar++> expr :: ExprParser () Int+> expr = proc () -> do+>		x <- term -< ()+>		expr' -< x++> expr' :: ExprParser Int Int+> expr' = proc x -> do+>		returnA -< x+>	<+> do+>		symbol Plus -< ()+>		y <- term -< ()+>		expr' -< x + y+>	<+> do+>		symbol Minus -< ()+>		y <- term -< ()+>		expr' -< x - y++> term :: ExprParser () Int+> term = proc () -> do+>		x <- factor -< ()+>		term' -< x++> term' :: ExprParser Int Int+> term' = proc x -> do+>		returnA -< x+>	<+> do+>		symbol Mult -< ()+>		y <- factor -< ()+>		term' -< x * y+>	<+> do+>		symbol Div -< ()+>		y <- factor -< ()+>		term' -< x `div` y++> factor :: ExprParser () Int+> factor = proc () -> do+>		v <- symbol Number -< ()+>		returnA -< read v::Int+>	<+> do+>		symbol Minus -< ()+>		v <- factor -< ()+>		returnA -< -v+>	<+> do+>		symbol LPar -< ()+>		v <- expr -< ()+>		symbol RPar -< ()+>		returnA -< v++Lexical analysis++> lexer :: String -> [ExprSym]+> lexer [] = []+> lexer ('(':cs) = Sym LPar "(":lexer cs+> lexer (')':cs) = Sym RPar ")":lexer cs+> lexer ('+':cs) = Sym Plus "+":lexer cs+> lexer ('-':cs) = Sym Minus "-":lexer cs+> lexer ('*':cs) = Sym Mult "*":lexer cs+> lexer ('/':cs) = Sym Div "/":lexer cs+> lexer (c:cs)+>	| isSpace c = lexer cs+>	| isDigit c = Sym Number (c:w):lexer cs'+>	| otherwise = Sym Unknown [c]:lexer cs+>		where (w,cs') = span isDigit cs++> run parser = runError (runParser parser)+>	(\(_, err) -> error ("parse error: " ++ err)) . lexer++> t = run expr
+ examples/Parser/Parser.lhs view
@@ -0,0 +1,254 @@+> {-# OPTIONS -F -pgmF arrowp-ext #-}++LL(1) parser combinators: an arrow-ized (and greatly cut-down) version+of those of "Deterministic, Error-Correcting Combinator Parsers", by+Swierstra and Duponcheel.  This version uses statically constructed+parse tables, but doesn't do error correction.++> module Parser(+>	Symbol(eof), Sym(Sym),+>	Parser, symbol, runParser+> ) where++> import Control.Arrow+> import Control.Arrow.Operations+> import Control.Arrow.Transformer+> import Control.Arrow.Transformer.Error+> import Control.Arrow.Transformer.State+> import Control.Arrow.Transformer.Static+> import Control.Category+> import Prelude hiding (id, (.))++We require a symbol for EOF, distinguished from all existing symbols:++> class (Ord s, Show s) => Symbol s where+>	eof :: s++Combine a token with other information++> data Sym s v = Sym s v++> token (Sym s _) = s+> value (Sym _ v) = v++> instance (Show s, Show v) => Show (Sym s v) where+>	showsPrec p (Sym s v) = showParen True+>		(shows s . showString ", " . shows v)++> eofSym :: Symbol s => Sym s v+> eofSym = Sym s (error (show s ++ " has no value"))+>	where	s = eof++A dynamic parser may fail or transform a list of symbols.++> type DynamicParser s v a = StateArrow [Sym s v] (ErrorArrow String a)++> liftDynamic :: ArrowChoice a => a b c -> DynamicParser s v a b c+> liftDynamic f = lift (lift f)++The auxilliary definitions fetchHead and advance, with their explicit+type signatures, are needed to avoid nasty type errors.++> fetchHead :: ArrowChoice a => DynamicParser s v a b (Sym s v)+> fetchHead = proc _ -> do+>		(s:_) <- fetch -< ()+>		returnA -< s++> getToken :: ArrowChoice a => DynamicParser s v a b s+> getToken = fetchHead >>> arr token++> advance :: ArrowChoice a => DynamicParser s v a b (Sym s v)+> advance = proc _ -> do+>		(s:ss) <- fetch -< ()+>		store -< ss+>		returnA -< s++The dynamic symbol parser ignores the symbol, as it will already have+been checked by the table lookup.++> unitDP :: ArrowChoice a => DynamicParser s v a b v+> unitDP = advance >>> arr value++Use the static information to construct a dynamic parser.++If the table is empty, we know statically that any lookup will fail.++> mkDynamic :: (Symbol s, ArrowChoice a) =>+>	Maybe (a b c) -> Table s (DynamicParser s v a b c) ->+>		DynamicParser s v a b c+> mkDynamic Nothing t = arr id &&& getToken >>> lookupTable t err+>	where	err = proc _ -> raise -< "expected " ++ show (keys t)+> mkDynamic (Just f) t+>	| isEmptyTable t = liftDynamic f+>	| otherwise = arr id &&& getToken >>> lookupTable t base+>	where	base = proc (b, _) -> liftDynamic f -< b++If a parser arrow can recognize the empty string, it needs a function+to transform input to output.++> data Parser s v a b c = SP {+>		emptyP :: StaticMonadArrow Maybe a b c,+>		table :: Table s (DynamicParser s v a b c),+>		dynamic :: DynamicParser s v a b c+>				-- dynamic = mkDynamic empty table+>	}++> mkParser :: (Symbol s, ArrowChoice a) =>+>	StaticMonadArrow Maybe a b c -> Table s (DynamicParser s v a b c) ->+>		Parser s v a b c+> mkParser e t = SP {+>		emptyP = e,+>		table = t,+>		dynamic = mkDynamic (unwrapM e) t+>	}++> symbol :: (Symbol s, ArrowChoice a) => s -> Parser s v a b v+> symbol s = mkParser (wrapM Nothing) (unitTable s unitDP)++> eofParser :: (Symbol s, ArrowChoice a) => Parser s v a b b+> eofParser = proc x -> do+>	symbol eof -< ()+>	returnA -< x++> instance (Symbol s, ArrowChoice a) => Arrow (Parser s v a) where+>	arr f = mkParser (arr f) emptyTable+>	first (SP{emptyP = e, table = t}) =+>		mkParser (first e) (fmap first t)++> instance (Symbol s, ArrowChoice a) => Category (Parser s v a) where+>       id = arr id+>	~SP{emptyP = e2, table = t2, dynamic = d2} . SP{emptyP = e1, table = t1} =+>		if isEmptyTable common+>		then mkParser (e1 >>> e2) (plusTable t1' t2')+>		else error ("parse conflict (concatenation) on " +++>				show (keys common))+>		where	common = intersectTable t1' t2'+>			t1' = fmap (>>> d2) t1+>			t2' = seqEmptyTable (unwrapM e1) t2+>			seqEmptyTable Nothing _ = emptyTable+>			seqEmptyTable (Just f) t = fmap (liftDynamic f >>>) t++> instance (Symbol s, ArrowChoice a) => ArrowZero (Parser s v a) where+>	zeroArrow = mkParser (wrapM Nothing) emptyTable++> instance (Symbol s, ArrowChoice a) => ArrowPlus (Parser s v a) where+>	SP{emptyP = e1, table = t1} <+> SP{emptyP = e2, table = t2} =+>		if isEmptyTable common+>		then mkParser (wrapM (plusEmpty (unwrapM e1) (unwrapM e2)))+>			      (plusTable t1 t2)+>		else error ("parse conflict (union) on " ++ show (keys common))+>		where	common = intersectTable t1 t2+>			plusEmpty Nothing e2 = e2+>			plusEmpty e1 Nothing = e1+>			plusEmpty _ _ = error "Empty-Empty"++> instance (Symbol s, ArrowChoice a, ArrowLoop a) =>+>		ArrowLoop (Parser s v a) where+>	loop (SP{emptyP = e, table = t}) =+>		mkParser (wrapM (fmap loop (unwrapM e))) (fmap loop t)++Run a parser on a complete input++> runParser :: (Symbol s, ArrowChoice a) =>+>	Parser s v a () b -> ErrorArrow String a [Sym s v] b+> runParser p = proc ss -> do+>			(v, _) <- rp -< ((), ss ++ [eofSym])+>			returnA -< v+>		where	rp = runState (dynamic (p >>> eofParser))++general combinators++> option :: ArrowPlus a => (b -> c) -> a b c -> a b c+> option f p = arr f <+> p++> many :: ArrowPlus a => a b c -> a b [c]+> many p = option (const []) (some p)++> some :: ArrowPlus a => a b c -> a b [c]+> some p = some_p+>	where	some_p = proc b -> do+>			c <- p -< b+>			cs <- many_p -< b+>			returnA -< c:cs+>		many_p = option (const []) (some_p)++A different design:++> optional :: ArrowPlus a => a b b -> a b b+> optional p = arr id <+> p++> star :: ArrowPlus a => a b b -> a b b+> star p = p' where p' = optional (p >>> p')++> plus :: ArrowPlus a => a b b -> a b b+> plus p = p' where p' = p >>> optional p'++Tables.++During parser construction, these are represented as lists of pairs,+ordered by the key.  Then these are transformed into balanced search+trees for use in parsing.++> newtype Table k v = Table [(k, v)]++> emptyTable :: Table k v+> emptyTable = Table []++> unitTable :: k -> v -> Table k v+> unitTable k v = Table [(k, v)]++> instance Functor (Table k) where+>	fmap f (Table kvs) = Table [(k, f v) | (k, v) <- kvs]++Combine two tables.  In case of conflicts, the first takes precedence.++> plusTable :: Ord k => Table k v -> Table k v -> Table k v+> plusTable (Table t1) (Table t2) = Table (merge t1 t2)+>	where	merge [] kvs2 = kvs2+>		merge kvs1 [] = kvs1+>		merge (kvs1@(p1@(k1, _):kvs1')) (kvs2@(p2@(k2, _):kvs2')) =+>			case compare k1 k2 of+>			LT -> p1:merge kvs1' kvs2+>			EQ -> p1:merge kvs1' kvs2'+>			GT -> p2:merge kvs1 kvs2'++> intersectTable :: Ord k => Table k v1 -> Table k v2 -> Table k (v1, v2)+> intersectTable (Table t1) (Table t2) = Table (merge t1 t2)+>	where	merge [] _ = []+>		merge _ [] = []+>		merge (kvs1@((k1, v1):kvs1')) (kvs2@((k2, v2):kvs2')) =+>			case compare k1 k2 of+>			LT -> merge kvs1' kvs2+>			EQ -> (k1, (v1, v2)):merge kvs1' kvs2'+>			GT -> merge kvs1 kvs2'++> isEmptyTable :: Table k v -> Bool+> isEmptyTable (Table t) = null t++> keys :: Table k v -> [k]+> keys (Table kvs) = map fst kvs++> data SearchTree k v = Empty | Node (SearchTree k v) k v (SearchTree k v)++Make a balanced search tree from a table++> searchTree :: Ord k => Table k v -> SearchTree k v+> searchTree (Table kvs) = fst (mkTree (length kvs) kvs)+>	where	mkTree :: Int -> [(k,v)] -> (SearchTree k v, [(k,v)])+>		mkTree n kvs = if n == 0 then (Empty, kvs)+>			else	let	size_l = (n-1) `div` 2+>					(l, (k, v):kvs') = mkTree size_l kvs+>					(r, kvs'') = mkTree (n-1-size_l) kvs'+>				in (Node l k v r, kvs'')++Construct an arrow that searches for dynamic inputs in the statically+constructed tree of arrows.++> lookupTable :: (ArrowChoice a, Ord k) =>+>	Table k (a b c) -> a (b, k) c -> a (b, k) c+> lookupTable t def = look (searchTree t)+>	where	look Empty = def+>		look (Node l k a r) = proc (v, x) -> case compare x k of+>			LT -> look l -< (v, x)+>			EQ -> a -< v+>			GT -> look r -< (v, x)
+ examples/TH/BackStateArrow.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE QuasiQuotes #-}+module TH.BackstateArrow where++import           Control.Arrow+import           Control.Arrow.QuasiQuoter+import           Control.Category+import           Prelude                   hiding (id, (.))++-- Generalizing the backwards state transformer monad mentioned+-- in Wadler's "The Essence of Functional Programming"++newtype BackStateArrow s a b c = BST (a (b,s) (c,s))++instance ArrowLoop a => Category (BackStateArrow s a) where+	BST g . BST f = BST $ [proc| (b, s) -> do+			rec	(c, s'') <- f -< (b, s')+				(d, s') <- g -< (c, s)+			returnA -< (d, s'')|]++instance ArrowLoop a => Arrow (BackStateArrow s a) where+	arr f = BST [proc| (b, s) ->+			returnA -< (f b, s)|]+	first (BST f) = BST $ [proc| ((b, d), s) -> do+			(c, s') <- f -< (b, s)+			returnA -< ((c, d), s')|]++instance (ArrowLoop a, ArrowChoice a) => ArrowChoice (BackStateArrow s a) where+	left (BST f) = BST $ [proc| (x, s) ->+		case x of+			Left b -> do+				(c, s') <- f -< (b, s)+				returnA -< (Left c, s')+			Right d ->+				returnA -< (Right d, s) |]++instance ArrowLoop a => ArrowLoop (BackStateArrow s a) where+	loop (BST f) = BST $  [proc| (b, s) -> do+			rec	((c, d), s') <- f -< ((b, d), s)+			returnA -< (c, s') |]
+ examples/TH/TH.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE Arrows      #-}+{-# LANGUAGE QuasiQuotes #-}+module TH.TH where+import           Control.Arrow+import           Control.Arrow.QuasiQuoter+import           Language.Haskell.TH++while :: ArrowChoice a => a b Bool -> a b () -> a b ()+while p s = proc x -> do+		b <- p -< x+		if b then do+				s -< x+				while p s -< x+			else+				returnA -< ()++test p s = [proc| x -> do+		b <- p -< x+		if b then do+				s -< x+				while p s -< x+			else+				returnA -< ()+            |]
+ examples/TH/While.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE QuasiQuotes #-}+module TH.While where++import           Control.Arrow+import           Control.Arrow.QuasiQuoter++addA :: Arrow a => a b Int -> a b Int -> a b Int+addA f g = [proc| x -> do+		y <- f -< x+		z <- g -< x+		returnA -< y + z |]++while :: ArrowChoice a => a b Bool -> a b () -> a b ()+while p s = [proc| x -> do+		b <- p -< x+		if b then do+				s -< x+				while p s -< x+			else+				returnA -< ()+              |]
+ examples/small/BackStateArrow.hs view
@@ -0,0 +1,39 @@+{- LANGUAGE Arrows -}+{-# OPTIONS -F -pgmF arrowp-ext #-}+module BackstateArrow where++import           Control.Arrow+import           Control.Category+import           Prelude          hiding (id, (.))++-- Generalizing the backwards state transformer monad mentioned+-- in Wadler's "The Essence of Functional Programming"++newtype BackStateArrow s a b c = BST (a (b,s) (c,s))++instance ArrowLoop a => Category (BackStateArrow s a) where+	BST g . BST f = BST $ proc (b, s) -> do+			rec	(c, s'') <- f -< (b, s')+				(d, s') <- g -< (c, s)+			returnA -< (d, s'')++instance ArrowLoop a => Arrow (BackStateArrow s a) where+	arr f = BST $ proc (b, s) ->+			returnA -< (f b, s)+	first (BST f) = BST $ proc ((b, d), s) -> do+			(c, s') <- f -< (b, s)+			returnA -< ((c, d), s')++instance (ArrowLoop a, ArrowChoice a) => ArrowChoice (BackStateArrow s a) where+	left (BST f) = BST $ proc (x, s) ->+		case x of+			Left b -> do+				(c, s') <- f -< (b, s)+				returnA -< (Left c, s')+			Right d ->+				returnA -< (Right d, s)++instance ArrowLoop a => ArrowLoop (BackStateArrow s a) where+	loop (BST f) = BST $ proc (b, s) -> do+			rec	((c, d), s') <- f -< ((b, d), s)+			returnA -< (c, s')
+ examples/small/Egs.hs view
@@ -0,0 +1,20 @@+{- LANGUAGE Arrows -}+{-# OPTIONS -F -pgmF arrowp-ext #-}+module Egs where++import           Control.Arrow++addA :: Arrow a => a b Int -> a b Int -> a b Int+addA f g = proc x -> do+		y <- f -< x+		z <- g -< x+		returnA -< y + z++while :: ArrowChoice a => a b Bool -> a b () -> a b ()+while p s = proc x -> do+		b <- p -< x+		if b then do+				s -< x+				while p s -< x+			else+				returnA -< ()
+ examples/small/Eval.hs view
@@ -0,0 +1,42 @@+{- LANGUAGE Arrows -}+{-# OPTIONS -F -pgmF arrowp-ext #-}+module Eval where++-- Toy lambda-calculus interpreter from John Hughes's arrows paper (s5)++import           Control.Arrow+import           Data.Maybe    (fromJust)++type Id = String+data Val a = Num Int | Bl Bool | Fun (a (Val a) (Val a))+data Exp = Var Id | Add Exp Exp | If Exp Exp Exp | Lam Id Exp | App Exp Exp++eval :: (ArrowChoice a, ArrowApply a) => Exp -> a [(Id, Val a)] (Val a)+eval (Var s) = proc env ->+		returnA -< fromJust (lookup s env)+eval (Add e1 e2) = proc env -> do+		~(Num u) <- eval e1 -< env+		~(Num v) <- eval e2 -< env+		returnA -< Num (u + v)+eval (If e1 e2 e3) = proc env -> do+		~(Bl b) <- eval e1 -< env+		if b	then eval e2 -< env+			else eval e3 -< env+eval (Lam x e) = proc env ->+		returnA -< Fun (proc v -> eval e -< (x,v):env)+eval (App e1 e2) = proc env -> do+		~(Fun f) <- eval e1 -< env+		v <- eval e2 -<< env+		f -< v++-- some tests++i = Lam "x" (Var "x")+k = Lam "x" (Lam "y" (Var "x"))+double = Lam "x" (Add (Var "x") (Var "x"))++t = n+	where Num n = eval (If (Var "b")+			(App (App k (App double (Var "x"))) (Var "x"))+			(Add (Var "x") (Add (Var "x") (Var "x"))))+		[("b", Bl True), ("x", Num 5)]
+ examples/small/Eval1.hs view
@@ -0,0 +1,45 @@+{- LANGUAGE Arrows -}+{-# OPTIONS -F -pgmF arrowp-ext #-}+module Eval1 where++-- Toy lambda-calculus interpreter from John Hughes's arrows paper (s5)++import           Control.Arrow+import           Data.Maybe    (fromJust)++type Id = String+data Val a = Num Int | Bl Bool | Fun (a (Val a) (Val a))+data Exp = Var Id | Add Exp Exp | If Exp Exp Exp | Lam Id Exp | App Exp Exp++eval :: (ArrowChoice a, ArrowApply a) => Exp -> a [(Id, Val a)] (Val a)+eval (Var s) = proc env ->+		returnA -< fromJust (lookup s env)+eval (Add e1 e2) = proc env ->+		(eval e1 -< env) `bind` \ ~(Num u) ->+		(eval e2 -< env) `bind` \ ~(Num v) ->+		returnA -< Num (u + v)+eval (If e1 e2 e3) = proc env ->+		(eval e1 -< env) `bind` \ ~(Bl b) ->+		if b then eval e2 -< env+			else eval e3 -< env+eval (Lam x e) = proc env ->+		returnA -< Fun (proc v -> eval e -< (x,v):env)+eval (App e1 e2) = proc env ->+		(eval e1 -< env) `bind` \ ~(Fun f) ->+		(eval e2 -< env) `bind` \ v ->+		f -< v++bind :: Arrow a => a b c -> a (b,c) d -> a b d+e `bind` f = returnA &&& e >>> f++-- some tests++i = Lam "x" (Var "x")+k = Lam "x" (Lam "y" (Var "x"))+double = Lam "x" (Add (Var "x") (Var "x"))++t = n+	where Num n = eval (If (Var "b")+			(App (App k (App double (Var "x"))) (Var "x"))+			(Add (Var "x") (Add (Var "x") (Var "x"))))+		[("b", Bl True), ("x", Num 5)]
+ examples/small/Lift.hs view
@@ -0,0 +1,13 @@+{- LANGUAGE Arrows -}+{-# OPTIONS -F -pgmF arrowp-ext #-}+module Lift where++import           Control.Arrow++-- lifting a binary operation to arrows (Hughes's paper, s4.1)++liftA2' :: Arrow a => (b -> c -> d) -> a e b -> a e c -> a e d+liftA2' op f g = proc x -> do+		y <- f -< x+		z <- g -< x+		returnA -< y `op` z
+ examples/small/ListOps.hs view
@@ -0,0 +1,29 @@+{- LANGUAGE Arrows -}+{-# OPTIONS -F -pgmF arrowp-ext #-}+module ListOps where++-- generalizing map and filter to arrows++-- Note that these need ArrowChoice (because they use case) but+-- not ArrowApply (because the arrows used before -< don't involve+-- variables defined inside the arrow abstraction).++import           Control.Arrow++mapA :: ArrowChoice a => a (b, c) d -> a (b, [c]) [d]+mapA f = proc (env, xs) -> case xs of+		[] ->+			returnA -< []+		x:xs -> do+			y <- f -< (env, x)+			ys <- mapA f -< (env, xs)+			returnA -< y:ys++filterA :: ArrowChoice a => a (b, c) Bool -> a (b, [c]) [c]+filterA p = proc (env, xs) -> case xs of+		[] ->+			returnA -< []+		x:xs -> do+			b <- p -< (env, x)+			ys <- filterA p -< (env, xs)+			returnA -< if b then x:ys else ys
+ src/ArrCode.hs view
@@ -0,0 +1,255 @@+{-# LANGUAGE DeriveFunctor        #-}+{-# LANGUAGE DeriveGeneric        #-}+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE OverloadedLists      #-}+{-# LANGUAGE ScopedTypeVariables  #-}+{-# LANGUAGE StandaloneDeriving   #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++module ArrCode (+      Arrow,+      bind, anon,+      arr, arrLet, (>>>), arrowExp, applyOp, infixOp, (|||), first,+      VarDecl(VarDecl), letCmd,+      context, anonArgs, toHaskell,+      Tuple(..),+      isEmptyTuple, unionTuple, minusTuple, intersectTuple,+      patternTuple, expTuple,+      returnA_exp, arr_exp, compose_op, choice_op, first_exp,+      left_exp, right_exp, app_exp, loop_exp,+      ifte, app, loop, returnA+      ) where+import           Data.Default+import           Data.Set                     (Set)+import qualified Data.Set                     as Set+import           Debug.Hoed.Pure+import           Language.Haskell.Exts.Syntax hiding (Let, Tuple)+import qualified Language.Haskell.Exts.Syntax as H+import           Utils++data Arrow = Arrow+  { context  :: Tuple -- named input components used by the arrow+  , anonArgs :: Int     -- number of unnamed arguments+  , code     :: Code+  }+  deriving (Eq, Generic, Show)++instance Located Arrow  where+  type LocType Arrow = S+  location f (Arrow context anon code)=+    Arrow <$> location f context <*> pure anon <*> location f code++instance Observable Arrow++data VarDecl a = VarDecl (Name S) a+      deriving (Functor, Generic)++instance (Located a, LocType a ~ S) => Located (VarDecl a) where+  type LocType (VarDecl a) = S+  location f (VarDecl n a) = VarDecl <$> location f n <*> location f a++-- required Undecidable instances+deriving instance (Eq a) => Eq (VarDecl a)+deriving instance (Show a) => Show (VarDecl a)++instance Observable a => Observable (VarDecl a)++data Code+      = ReturnA                       -- returnA = arr id+      | Arr Int (Pat S) [Binding] (Exp S)   -- arr (first^n (\p -> ... e))+      | Compose Code [Code] Code  -- composition of 2 or more elts+      | Op (Exp S) [Code]         -- combinator applied to arrows+      | InfixOp Code (QOp S) Code+      | Let [VarDecl Code] Code+      | Ifte (Exp S) Code Code+  deriving (Eq, Generic, Show)++instance Located Code where+  type LocType Code = S+  location _ ReturnA = pure ReturnA+  location f (Arr i pat bb e) =+    Arr i <$> location f pat <*> location f bb <*> location f e+  location f (Compose c1 cc c2) =+    Compose <$> location f c1 <*> location f cc <*> location f c2+  location f (Op e cc) = Op <$> location f e <*> location f cc+  location f (InfixOp c qop c') = InfixOp <$> location f c <*> location f qop <*> location f c'+  location f (Let vv c) = Let <$> location f vv <*> location f c+  location f (Ifte e c1 c2) = Ifte <$> location f e <*> location f c1 <*> location f c2++instance Observable Code++data Binding = BindLet (Binds S) | BindCase (Pat S) (Exp S)+  deriving (Eq,Generic, Show)+instance Observable Binding++instance Located Binding where+  type LocType Binding = S+  location f (BindLet b) = BindLet <$> location f b+  location f (BindCase p e) = BindCase <$> location f p <*> location f e++loop :: Arrow -> Arrow+loop f = applyOp loop_exp [f]++app, returnA :: Arrow+app = arrowExp app_exp+returnA = arrowExp returnA_exp++bind :: Set (Name S) -> Arrow -> Arrow+bind = observe "bind" $ \vars a -> a {context = context a `minusTuple` vars}+anon :: Int -> Arrow -> Arrow+anon anonCount a = a {anonArgs = anonArgs a + anonCount}+arr+  :: Int -> Tuple -> Pat S -> Exp S -> Arrow+arr = observe "arr" $ \anons t p e ->+  Arrow+  { code =+      if same p e+        then ReturnA+        else Arr anons p [] e+  , context = t `intersectTuple` freeVars e+  , anonArgs = anons+  }+arrLet :: Int -> Tuple -> Pat S -> Binds S -> Exp S -> Arrow+arrLet anons t p ds e =+  Arrow+  { code = Arr anons p [BindLet ds] e+  , context = t `intersectTuple` vs+  , anonArgs = anons+  }+  where+    vs =+      (freeVars e `Set.union` freeVarss ds) `Set.difference` definedVars ds+ifte :: Exp S -> Arrow -> Arrow -> Arrow+ifte c th el =+  Arrow+  { code = Ifte c (code th) (code el)+  , context = context th `unionTuple` context el+  , anonArgs = 0+  }+(>>>) :: Arrow -> Arrow -> Arrow+a1 >>> a2 = a1 { code = compose (code a1) (code a2) }+arrowExp :: Exp S -> Arrow+arrowExp e =+  Arrow+  { code =+      if e == returnA_exp+        then ReturnA+        else Op e []+  , context = emptyTuple+  , anonArgs = 0+  }+applyOp :: Exp S -> [Arrow] -> Arrow+applyOp e as =+  Arrow+  { code = Op e (map code as)+  , context = foldr (unionTuple . context) emptyTuple as+  , anonArgs = 0 -- BUG: see below+  }++infixOp :: Arrow -> QOp S -> Arrow -> Arrow+infixOp a1 op a2 =+  Arrow+  { code = InfixOp (code a1) op (code a2)+  , context = context a1 `unionTuple` context a2+  , anonArgs = 0 -- BUG: as above+  }+first :: Arrow -> Tuple -> Arrow+first a ps =+  Arrow+  { code = Op first_exp [code a]+  , context = context a `unionTuple` ps+  , anonArgs = 0+  }+(|||) :: Arrow -> Arrow -> Arrow+a1 ||| a2 =+  Arrow+  { code = InfixOp (code a1) choice_op (code a2)+  , context = context a1 `unionTuple` context a2+  , anonArgs = 0+  }+letCmd :: [VarDecl Arrow] -> Arrow -> Arrow+letCmd defs a =+  Arrow+  { code = Let (map (fmap code) defs) (code a)+  , context = context a+  , anonArgs = anonArgs a+  }++compose :: Code -> Code -> Code+compose = observe "compose" compose'++compose' :: Code -> Code -> Code+compose' ReturnA a = a+compose' a ReturnA = a+compose' a1@(Arr n1 p1 ds1 e1) a2@(Arr n2 p2 ds2 e2)+  | n1 /= n2 = Compose a1 [] a2 -- could do better, but can this arise?+  | same p2 e1 = Arr n1 p1 (ds1 ++ ds2) e2+  | otherwise = Arr n1 p1 (ds1 ++ BindCase p2 e1 : ds2) e2+compose' (Compose f1 as1 g1) (Compose f2 as2 g2) =+  Compose f1 (as1 ++ (g1 : f2 : as2)) g2+compose' a (Compose f bs g) = Compose (compose a f) bs g+compose' (Compose f as g) b = Compose f as (compose g b)+compose' a1 a2 = Compose a1 [] a2++toHaskell :: Arrow -> Exp S+toHaskell = rebracket1 . toHaskellCode . code+  where+    toHaskellCode :: Code -> Exp S+    toHaskellCode ReturnA = returnA_exp+    toHaskellCode (Arr n p bs e) =+      App def arr_exp (times n (Paren def . App def first_exp) body)+      where+        body = Lambda def [p] (foldr addBinding e bs)+        addBinding (BindLet ds) e = H.Let def ds e+        addBinding (BindCase p e) e' =+          Case def e [Alt def p (UnGuardedRhs def e') Nothing]+    toHaskellCode (Compose f as g) =+      foldr (comp . toHaskellArg) (toHaskellArg g) (f : as)+      where+        comp f = InfixApp def f compose_op+    toHaskellCode (Op op as) = foldl (App def) op (map (Paren def . toHaskellCode) as)+    toHaskellCode (InfixOp a1 op a2) =+      InfixApp def (toHaskellArg a1) op (toHaskellArg a2)+    toHaskellCode (Let nas a) =+      H.Let def (BDecls def $ map toHaskellDecl nas) (toHaskellCode a)+      where+        toHaskellDecl (VarDecl n a) =+          PatBind def (PVar def n) (UnGuardedRhs def (toHaskellCode a)) Nothing+    toHaskellCode (Ifte cond th el) = If def cond (toHaskellCode th) (toHaskellCode el)++    toHaskellArg = Paren def . toHaskellCode++newtype Tuple = Tuple (Set (Name S))+  deriving (Eq,Generic,Show)+instance Observable Tuple++instance Located Tuple where+  type LocType Tuple = S+  location f (Tuple names) = Tuple <$> location f names++isEmptyTuple :: Tuple -> Bool+isEmptyTuple (Tuple t) = Set.null t++patternTuple :: Tuple -> Pat S+patternTuple (Tuple [])  = PApp def (unit_con_name def) []+patternTuple (Tuple [x]) = PVar def x+patternTuple (Tuple t)   = PTuple def Boxed (map (PVar def) (Set.toList t))++expTuple :: Tuple -> Exp S+expTuple (Tuple [])  = unit_con def+expTuple (Tuple [t]) = Var def $ UnQual def t+expTuple (Tuple t)   = H.Tuple def Boxed (map (Var def . UnQual def) (Set.toList t))++emptyTuple :: Tuple+emptyTuple = Tuple Set.empty+unionTuple :: Tuple -> Tuple -> Tuple+unionTuple (Tuple a) (Tuple b) = Tuple (a `Set.union` b)++minusTuple :: Tuple -> Set (Name S) -> Tuple+Tuple t `minusTuple` vs = Tuple (t `Set.difference` vs)+intersectTuple :: Tuple -> Set (Name S) -> Tuple+intersectTuple = observe "intersectTuple" intersectTuple'+intersectTuple' :: Tuple -> Set (Name S) -> Tuple+Tuple t `intersectTuple'` vs = Tuple (t `Set.intersection` vs)
− src/ArrCode.lhs
@@ -1,245 +0,0 @@-> module ArrCode(->	Arrow,->	bind, anon,->	arr, arrLet, (>>>), arrowExp, applyOp, infixOp, (|||), first,->	VarDecl(VarDecl), letCmd,->	context, anonArgs, toHaskell,->	Tuple(..),->	isEmptyTuple, unionTuple, minusTuple, intersectTuple,->	patternTuple, expTuple,->	returnA_exp, arr_exp, compose_op, choice_op, first_exp,->	left_exp, right_exp, app_exp, loop_exp,->       ifte-> ) where--> import Utils--> import Data.Set (Set)-> import qualified Data.Set as Set-> import Language.Haskell.Syntax--> data Arrow = Arrow {->		code :: Code,->		context :: Tuple, -- named input components used by the arrow->		anonArgs :: Int   -- number of unnamed arguments->	}--> data VarDecl a = VarDecl SrcLoc HsName a->	deriving (Eq,Show)--> instance Functor VarDecl where->	fmap f (VarDecl loc name a) = VarDecl loc name (f a)--> data Code->	= ReturnA			-- returnA = arr id->	| Arr Int HsPat [Binding] HsExp	-- arr (first^n (\p -> ... e))->	| Compose Code [Code] Code	-- composition of 2 or more elts->	| Op HsExp [Code]		-- combinator applied to arrows->	| InfixOp Code HsQOp Code->	| Let [VarDecl Code] Code->       | Ifte HsExp Code Code--> data Binding = BindLet [HsDecl] | BindCase HsPat HsExp--------------------------------------------------------------------------------Arrow constants--> compose_op, choice_op :: HsQOp-> returnA_exp, arr_exp, first_exp :: HsExp-> left_exp, right_exp, app_exp, loop_exp :: HsExp--> returnA_exp	= HsVar (UnQual (HsIdent "returnA"))-> arr_exp	= HsVar (UnQual (HsIdent "arr"))-> compose_op	= HsQVarOp (UnQual (HsSymbol ">>>"))-> choice_op	= HsQVarOp (UnQual (HsSymbol "|||"))-> first_exp	= HsVar (UnQual (HsIdent "first"))-> left_exp	= HsCon (UnQual (HsIdent "Left"))-> right_exp	= HsCon (UnQual (HsIdent "Right"))-> app_exp	= HsVar (UnQual (HsIdent "app"))-> loop_exp	= HsVar (UnQual (HsIdent "loop"))--------------------------------------------------------------------------------Arrow constructors--> bind :: Set HsName -> Arrow -> Arrow-> bind vars a = a {->		context = context a `minusTuple` vars->	}--> anon :: Int -> Arrow -> Arrow-> anon anonCount a = a {->		anonArgs = anonArgs a + anonCount->	}--> arr :: Int -> Tuple -> HsPat -> HsExp -> Arrow-> arr anons t p e = Arrow {->		code = if same p e then ReturnA else Arr anons p [] e,->		context = t `intersectTuple` freeVars e,->		anonArgs = anons->	}->	where	same :: HsPat -> HsExp -> Bool->		same (HsPApp n1 []) (HsCon n2) = n1 == n2->		same (HsPVar n1) (HsVar n2) = UnQual n1 == n2->		same (HsPTuple ps) (HsTuple es) =->			length ps == length es && and (zipWith same ps es)->		same (HsPAsPat n p) e = e == HsVar (UnQual n) || same p e->		same (HsPParen p) e = same p e->		same p (HsParen e) = same p e->		same _ _ = False	-- other cases don't arise--> arrLet :: Int -> Tuple -> HsPat -> [HsDecl] -> HsExp -> Arrow-> arrLet anons t p ds e = Arrow {->		code = Arr anons p [BindLet ds] e,->		context = t `intersectTuple` vs,->		anonArgs = anons->	}->	where	vs = (freeVars e `Set.union` freeVars ds)->				`Set.difference` definedVars ds--> ifte :: HsExp -> Arrow -> Arrow -> Arrow-> ifte c th el = Arrow->             { code = Ifte c (code th) (code el)->             , context = context th `unionTuple` context el->             , anonArgs = 0->             }--> (>>>) :: Arrow -> Arrow -> Arrow-> a1 >>> a2 = a1 { code = compose (code a1) (code a2) }--> arrowExp :: HsExp -> Arrow-> arrowExp e = Arrow {->		code = if e == returnA_exp then ReturnA else Op e [],->		context = emptyTuple,->		anonArgs = 0->	}--> applyOp :: HsExp -> [Arrow] -> Arrow-> applyOp e as = Arrow {->		code = Op e (map code as),->		context = foldr unionTuple emptyTuple (map context as),->		anonArgs = 0	-- BUG: see below->	}--Setting anonArgs to 0 for infixOp is incorrect, but we can't know the-correct value without types.--> infixOp :: Arrow -> HsQOp -> Arrow -> Arrow-> infixOp a1 op a2 = Arrow {->		code = InfixOp (code a1) op (code a2),->		context = context a1 `unionTuple` context a2,->		anonArgs = 0	-- BUG: as above->	}--> first :: Arrow -> Tuple -> Arrow-> first a ps = Arrow {->		code = Op first_exp [code a],->		context = context a `unionTuple` ps,->		anonArgs = 0->	}--> (|||) :: Arrow -> Arrow -> Arrow-> a1 ||| a2 = Arrow {->		code = InfixOp (code a1) choice_op (code a2),->		context = context a1 `unionTuple` context a2,->		anonArgs = 0->	}--> letCmd :: [VarDecl Arrow] -> Arrow -> Arrow-> letCmd defs a = Arrow {->		code = Let (map (fmap code) defs) (code a),->		context = context a,->		anonArgs = anonArgs a->	}--Composition, with some simplification--> compose :: Code -> Code -> Code-> compose ReturnA a = a-> compose a ReturnA = a-> compose a1@(Arr n1 p1 ds1 e1) a2@(Arr n2 p2 ds2 e2)->	| n1 /= n2 = Compose a1 [] a2	-- could do better, but can this arise?->	| same p2 e1 = Arr n1 p1 (ds1 ++ ds2) e2->	| otherwise = Arr n1 p1 (ds1 ++ BindCase p2 e1:ds2) e2->	where	same :: HsPat -> HsExp -> Bool->		same (HsPApp n1 []) (HsCon n2) = n1 == n2->		same (HsPVar n1) (HsVar n2) = UnQual n1 == n2->		same (HsPTuple ps) (HsTuple es) =->			length ps == length es && and (zipWith same ps es)->		same (HsPParen p) e = same p e->		same p (HsParen e) = same p e->		same _ _ = False	-- other cases don't arise-> compose (Compose f1 as1 g1) (Compose f2 as2 g2) =->	Compose f1 (as1 ++ (compose g1 f2 : as2)) g2-> compose a (Compose f bs g) =->	Compose (compose a f) bs g-> compose (Compose f as g) b =->	Compose f as (compose g b)-> compose a1 a2 =->	Compose a1 [] a2--------------------------------------------------------------------------------Conversion to Haskell--> toHaskell :: Arrow -> HsExp-> toHaskell = toHaskellCode . code--> toHaskellCode :: Code -> HsExp-> toHaskellCode ReturnA =->	returnA_exp-> toHaskellCode (Arr n p bs e) =->	HsApp arr_exp->		(times n (HsParen . HsApp first_exp) body)->	where	body = HsParen (HsLambda undefined [p] (foldr addBinding e bs))->		addBinding :: Binding -> HsExp -> HsExp->		addBinding (BindLet ds) e = HsLet ds e->		addBinding (BindCase p e) e' =->			HsCase e [HsAlt undefined p (HsUnGuardedAlt e') []]-> toHaskellCode (Compose f as g) =->	foldr comp (toHaskellArg g) (map toHaskellArg (f:as))->	where	comp f g = HsInfixApp f compose_op g-> toHaskellCode (Op op as) =->	foldl HsApp op (map (paren . toHaskellCode) as)-> toHaskellCode (InfixOp a1 op a2) =->	HsInfixApp (toHaskellArg a1) op (toHaskellArg a2)-> toHaskellCode (Let nas a) =->	HsLet (map toHaskellDecl nas) (toHaskellCode a)->	where	toHaskellDecl (VarDecl loc n a) =->			HsPatBind loc (HsPVar n)->				(HsUnGuardedRhs (toHaskellCode a)) []-> toHaskellCode (Ifte cond th el) = HsIf cond (toHaskellCode th) (toHaskellCode el)--> toHaskellArg :: Code -> HsExp-> toHaskellArg a = parenInfixArg (toHaskellCode a)--------------------------------------------------------------------------------Tuples, representing sets of variables.--> newtype Tuple = Tuple (Set HsName)--Tuple extractors, including matching expression and pattern.--> isEmptyTuple :: Tuple -> Bool-> isEmptyTuple (Tuple t) = Set.null t--> patternTuple :: Tuple -> HsPat-> patternTuple (Tuple t) = tupleP (map HsPVar (Set.toList t))--> expTuple :: Tuple -> HsExp-> expTuple (Tuple t) = tuple (map (HsVar . UnQual) (Set.toList t))--Operations on tuples--> emptyTuple :: Tuple-> emptyTuple = Tuple Set.empty--> unionTuple :: Tuple -> Tuple -> Tuple-> unionTuple (Tuple a) (Tuple b) = Tuple (a `Set.union` b)--Remove all usages of a set of variables.--> minusTuple :: Tuple -> Set HsName -> Tuple-> Tuple t `minusTuple` vs = Tuple (t `Set.difference` vs)--> intersectTuple :: Tuple -> Set HsName -> Tuple-> Tuple t `intersectTuple` vs = Tuple (t `Set.intersection` vs)-
+ src/ArrSyn.hs view
@@ -0,0 +1,243 @@+{-# LANGUAGE ConstraintKinds      #-}+{-# LANGUAGE DeriveGeneric        #-}+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE ScopedTypeVariables  #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+module ArrSyn+  ( translate+  ) where++import           ArrCode+import           Utils++import           Control.Monad.Trans.State+import           Data.List                  (mapAccumL)+import           Data.Map                   (Map)+import qualified Data.Map                   as Map+import           Data.Set                   (Set)+import qualified Data.Set                   as Set+import           Debug.Hoed.Pure+import           Language.Haskell.Exts      (Alt (..), Binds (..), Decl (..),+                                             Exp (), GuardedRhs (..),+                                             Match (..), Name, Pat (..),+                                             Rhs (..), Stmt (..), ann)++import qualified Language.Haskell.Exts      as H++-- -----------------------------------------------------------------------------+-- Translation to Haskell++-- This is a 2-phase process:+-- - transCmd' generates an abstract arrow combinator language represented+--   by the Arrow type, and+-- - toHaskell turns that into Haskell.++translate :: Pat S -> Exp S -> Exp S+translate p c = H.Paren (ann c) $ toHaskell (transCmd s p' c)+      where   (s, p') = startPattern p++startPattern :: Pat S -> (TransState, Pat S)+startPattern = observe "startPattern" startPattern'++startPattern' :: Pat S -> (TransState, Pat S)+startPattern' p =+      (TransState {+              locals = definedVars p,+              cmdVars = Map.empty+       }, p)+-- The pattern argument is often pseudo-recursively defined in terms of+-- the context part of the result of these functions.  (It's not real+-- recursion, because that part is independent of the pattern.)++transCmd :: TransState -> Pat S -> Exp S -> Arrow+transCmd = observe "transCmd" transCmd'++transCmd' :: TransState -> Pat S -> Exp S -> Arrow+transCmd' s p (H.LeftArrApp l f e)+      | Set.null (freeVars f `Set.intersection` locals s) =+              arr 0 (input s) p e >>> arrowExp f+      | otherwise =+              arr 0 (input s) p (pair f e) >>> app+transCmd' s p (H.LeftArrHighApp  l f e) = transCmd s p (H.LeftArrApp l f e)+transCmd' s p (H.RightArrApp     l f e) = transCmd s p (H.LeftArrApp l e f)+transCmd' s p (H.RightArrHighApp l f e) = transCmd s p (H.LeftArrHighApp l e f)+transCmd' s p (H.InfixApp l c1 op c2) =+  infixOp (transCmd s p c1) op (transCmd s p c2)+transCmd' s p (H.Let l decls c) =+      arrLet (anonArgs a) (input s) p decls' e >>> a+      where   (s', decls') = addVars' s decls+              (e, a) = transTrimCmd s' c+transCmd' s p (H.If l e c1 c2)+  | Set.null (freeVars e `Set.intersection` locals s) =+      ifte e (transCmd s p c1) (transCmd s p c2)+  | otherwise =+      arr 0 (input s) p (H.If l e (left e1) (right e2)) >>> (a1 ||| a2)+      where   (e1, a1) = transTrimCmd s c1+              (e2, a2) = transTrimCmd s c2+transCmd' s p (H.Case l e as) =+   arr 0 (input s) p (H.Case l e as') >>> foldr1 (|||) (reverse cases)+  where+    (as', (ncases, cases)) = runState (mapM (transAlt s) as) (0, [])+    transAlt = observeSt "transAlt" transAlt'+    transAlt' s (Alt loc p gas decls) = do+      let (s', p') = addVars' s p+          (s'', decls') = addVars' s' decls+      gas' <- transGuardedRhss s'' gas+      return (H.Alt loc p' gas' decls')+    transGuardedRhss = observeSt "transGuardedRhss" transGuardedRhss'+    transGuardedRhss' s (UnGuardedRhs l c) = do+      body <- newAlt s c+      return (H.UnGuardedRhs l body)+    transGuardedRhss' s (GuardedRhss l gas) = do+      gas' <- mapM (transGuardedRhs s) gas+      return (H.GuardedRhss l gas')+    transGuardedRhs = observeSt "transGuardedRhs" transGuardedRhs'+    transGuardedRhs' s (GuardedRhs loc e c) = do+      body <- newAlt s c+      return (H.GuardedRhs loc e body)+    newAlt = observeSt "newAlt" newAlt'+    newAlt' s c = do+      let (e, a) =+            transTrimCmd s c+      (n, as) <- get+      put (n + 1, a : as)+      return (label n e)+    label = observe "label" label'+    label' n e =+      times+        n+        right+        (if n < ncases - 1+           then left e+           else e)+transCmd' s p (H.Paren _ c) =+      transCmd s p c+transCmd' s p (H.Do l ss) =+      transDo s p (init ss) (let Qualifier _ e = last ss in e)+transCmd' s p (H.App l c arg) =+      anon (-1) $+      arr (anonArgs a) (input s) p (pair e arg) >>> a+      where   (e, a) = transTrimCmd s c+transCmd' s p (H.Lambda l ps c) =+  anon (length ps) $ bind (definedVars ps) $ transCmd s' (foldl pairP p ps') c+  where+    (s', ps') = addVars' s ps+transCmd' _ _ x = error $ "transCmd: " ++ show x++-- transCmd' s p (CmdVar n) =+--       arr (anonArgs a) (input s) p e >>> arrowExp (H.Var () (H.UnQual () n))+--       where   Just a = Map.lookup n (cmdVars s)+--               e = expTuple (context a)++-- Like TransCmd, but use the minimal input pattern.  The first component+-- of the result is the matching expression to build this input.+-- That is, the result is (e, proc p' -> c) with the minimal p' such that++-- 	proc p -> c = arr (first^n (p -> e)) >>> (proc p' -> c)++-- where n is the number of anonymous arguments taken by c.+transTrimCmd :: TransState -> Exp S -> (Exp S, Arrow)+transTrimCmd = observe "transTrimCmd" transTrimCmd'+transTrimCmd' :: TransState -> Exp S -> (Exp S, Arrow)+transTrimCmd' s c = (expTuple (context a), a)+      where   a = transCmd s (patternTuple (context a)) c++transDo :: TransState -> Pat S -> [Stmt S] -> Exp S -> Arrow+transDo = observe "transDo" transDo'++transDo' :: TransState -> Pat S -> [Stmt S] -> Exp S -> Arrow+transDo' s p [] c =+      transCmd s p c+transDo' s p (Qualifier l exp : ss) c =+  transDo' s p (Generator l (PWildCard l) exp : ss) c+transDo' s p (Generator l pg cg:ss) c =+      if isEmptyTuple u then+        transCmd s p cg >>> transDo s' pg ss c+      else+        arr 0 (input s) p (pair eg (expTuple u)) >>> first ag u >>> a+      where   (s', pg') = addVars' s pg+              a = observe "a" $ bind (definedVars pg)+                      (transDo s' (pairP pg' (patternTuple u)) ss c)+              u = observe "u" $ context a+              (eg, ag) = transTrimCmd s cg+transDo' s p (LetStmt l decls : ss) c =+      transCmd s p (H.Let l decls (H.Do l (ss ++ [Qualifier l c])))+transDo' s p (RecStmt l rss:ss) c =+  bind+    defined+    (loop+       (transDo+          s'+          (pairP p (irrPat (patternTuple feedback)))+          rss'+          (returnCmd (pair output (expTuple feedback)))) >>>+     a)+  where+    defined = foldMap definedVars rss+    (s', rss') = addVars' s rss+    (output, a) = transTrimCmd s' (H.Do l (ss ++ [Qualifier l c]))+    feedback =+      context+        (transDo+           s'+           p+           rss'+           (returnCmd+              (foldr (pair . H.Var l . H.UnQual l) output (Set.toList defined)))) `intersectTuple`+      defined++data TransState = TransState {+      locals  :: Set (Name S),   -- vars in scope defined in this proc+      cmdVars :: Map (Name S) Arrow+  } deriving (Eq, Generic, Show)++instance Observable TransState++input :: TransState -> Tuple+input s = Tuple (locals s)++addVars'+  :: (Observable a, AddVars a, Eq l, Show l, l ~ LocType a)+  => TransState -> a -> (TransState, a)+addVars' = observe "addVars" addVars++class AddVars a where+      addVars :: TransState -> a -> (TransState, a)++instance AddVars a => AddVars [a] where+      addVars = mapAccumL addVars++instance AddVars a => AddVars (Maybe a) where+  addVars = mapAccumL addVars++instance AddVars (Pat S) where+      addVars s p =+              (s {locals = locals s `Set.union` definedVars p}, p)++instance AddVars (Decl S) where+      addVars s d@(FunBind l (Match _ n _ _ _:_)) =+              (s', d)+              where   (s', _) = addVars s (PVar l n)+      addVars s (PatBind loc p rhs decls) =+              (s', PatBind loc p' rhs decls)+              where   (s', p') = addVars s p+      addVars s d = (s, d)++instance AddVars (Stmt S) where+      addVars s it@Qualifier{} = (s, it)+      addVars s (Generator loc p c) =+              (s', Generator loc p' c)+              where   (s', p') = addVars s p+      addVars s (LetStmt l decls) =+              (s', LetStmt l decls')+              where   (s', decls') = addVars s decls+      addVars s (RecStmt l stmts) =+              (s', RecStmt l stmts')+              where   (s', stmts') = addVars s stmts++instance AddVars (Binds S) where+  addVars s (BDecls l decls) = BDecls l <$> addVars s decls+  addVars s it@IPBinds{}     = (s, it)
− src/ArrSyn.lhs
@@ -1,304 +0,0 @@-Additional abstract syntax for arrow expressions--> module ArrSyn(->	Cmd(..),->	Stmts, Stmt(..), CmdDecl, VarDecl(..),->	Alt(..), GuardedAlts(..), GuardedAlt(..),->	translate	-- :: HsPat -> Cmd -> HsExp-> ) where--> import ArrCode-> import State		-- Haskell 98 version of Control.Monad.State-> import Utils--> import Data.List(mapAccumL)-> import Data.Map (Map)-> import qualified Data.Map as Map-> import Data.Set (Set)-> import qualified Data.Set as Set-> import Language.Haskell.Syntax--> data Cmd->	= Input HsExp HsExp->	| Kappa SrcLoc [HsPat] Cmd->	| Op HsExp [Cmd]->	| InfixOp Cmd HsQOp Cmd->	| Let [HsDecl] Cmd->	| LetCmd (VarDecl Cmd) Cmd->	| If HsExp Cmd Cmd->	| Case HsExp [Alt]->	| Paren Cmd->	| Do [Stmt] Cmd->	| App Cmd HsExp->	| CmdVar HsName->   deriving (Eq,Show)--> type CmdDecl = (HsName, Cmd)-> type Stmts = ([Stmt], Cmd)--> data Stmt->	= Generator SrcLoc HsPat Cmd->	| RecStmt [Stmt]->	| LetStmt [HsDecl]->	| LetCmdStmt (VarDecl Cmd)->   deriving (Eq,Show)--> data Alt->	= Alt SrcLoc HsPat GuardedAlts [HsDecl]->   deriving (Eq,Show)--> data GuardedAlts->	= UnGuardedAlt Cmd->	| GuardedAlts [GuardedAlt]->   deriving (Eq,Show)--> data GuardedAlt->	= GuardedAlt SrcLoc HsExp Cmd->   deriving (Eq,Show)--------------------------------------------------------------------------------Utilities--> pair :: HsExp -> HsExp -> HsExp-> pair e1 e2 = HsTuple [e1, e2]--Turn redefined variables into wildcards, so the new pattern will be legal.--> pairP :: HsPat -> HsPat -> HsPat-> pairP p1 p2 = HsPTuple [hide p1, p2]->	where	vs = freeVars p2->		hide p@(HsPVar n)->			| n `Set.member` vs = HsPWildCard->			| otherwise = p->		hide (HsPNeg p) = HsPNeg (hide p)->		hide (HsPInfixApp p1 n p2) = HsPInfixApp (hide p1) n (hide p2)->		hide (HsPApp n ps) = HsPApp n (map hide ps)->		hide (HsPTuple ps) = HsPTuple (map hide ps)->		hide (HsPList ps) = HsPList (map hide ps)->		hide (HsPParen p) = HsPParen (hide p)->		hide (HsPRec n pfs) = HsPRec n (map hideField pfs)->			where	hideField (HsPFieldPat f p) =->					HsPFieldPat f (hide p)->		hide (HsPAsPat n p)->			| n `Set.member` vs = hide p->			| otherwise = HsPAsPat n (hide p)->		hide (HsPIrrPat p) = HsPIrrPat (hide p)->		hide p = p--> left, right :: HsExp -> HsExp-> left f = HsApp left_exp (paren f)-> right f = HsApp right_exp (paren f)--> loop :: Arrow -> Arrow-> loop f = applyOp loop_exp [f]--> app, returnA :: Arrow-> app = arrowExp app_exp-> returnA = arrowExp returnA_exp--> returnCmd :: HsExp -> Cmd-> returnCmd = Input returnA_exp--------------------------------------------------------------------------------Translation state--> data TransState = TransState {->	locals :: Set HsName,	-- vars in scope defined in this proc->	cmdVars :: Map HsName Arrow-> }--> input :: TransState -> Tuple-> input s = Tuple (locals s)--> startPattern :: HsPat -> (TransState, HsPat)-> startPattern p =->	(TransState {->		locals = freeVars p,->		cmdVars = Map.empty->	 }, p)--> class AddVars a where->	addVars :: TransState -> a -> (TransState, a)--> instance AddVars a => AddVars [a] where->	addVars = mapAccumL addVars--> instance AddVars HsPat where->	addVars s p =->		(s {locals = locals s `Set.union` freeVars p}, p)---> instance AddVars HsDecl where->	addVars s d@(HsFunBind (HsMatch _ n _ _ _:_)) =->		(s', d)->		where	(s', _) = addVars s (HsPVar n)->	addVars s (HsPatBind loc p rhs decls) =->		(s', HsPatBind loc p' rhs decls)->		where	(s', p') = addVars s p->	addVars s d = (s, d)--------------------------------------------------------------------------------Translation to Haskell--This is a 2-phase process:-- transCmd generates an abstract arrow combinator language represented-  by the Arrow type, and-- toHaskell turns that into Haskell.--> translate :: HsPat -> Cmd -> HsExp-> translate p c = paren (toHaskell (transCmd s p' c))->	where	(s, p') = startPattern p--The pattern argument is often pseudo-recursively defined in terms of-the context part of the result of these functions.  (It's not real-recursion, because that part is independent of the pattern.)--> transCmd :: TransState -> HsPat -> Cmd -> Arrow-> transCmd s p (Input f e)->	| Set.null (freeVars f `Set.intersection` locals s) =->		arr 0 (input s) p e >>> arrowExp f->	| otherwise =->		arr 0 (input s) p (pair f e) >>> app-> transCmd s p (Kappa _ ps c) =->	anon (length ps) $ bind (freeVars ps) $->		transCmd s' (foldl pairP p ps') c->	where	(s', ps') = addVars s ps-> transCmd s p (Op op cs) =->	applyOp op (map (transCmd s p) cs)-> transCmd s p (InfixOp c1 op c2) =->	infixOp (transCmd s p c1) op (transCmd s p c2)-> transCmd s p (Let decls c) =->	arrLet (anonArgs a) (input s) p decls' e >>> a->	where	(s', decls') = addVars s decls->		(e, a) = transTrimCmd s' c-> transCmd s p (If e c1 c2)->   | Set.null (freeVars e `Set.intersection` locals s) =->       ifte e (transCmd s p c1) (transCmd s p c2)->   | otherwise =->	arr 0 (input s) p (HsIf e (left e1) (right e2)) >>> (a1 ||| a2)->	where	(e1, a1) = transTrimCmd s c1->		(e2, a2) = transTrimCmd s c2-> transCmd s p (Case e as) =->	transCase s p e as-> transCmd s p (Paren c) =->	transCmd s p c-> transCmd s p (Do ss c) =->	transDo s p ss c-> transCmd s p (App c arg) =->	anon (-1) $->	arr (anonArgs a) (input s) p (pair e arg) >>> a->	where	(e, a) = transTrimCmd s c--The following awful hack is there because if the command is recursively-defined, computation of its context will not terminate.  So we plug in-returnA (empty context) to get an arrow whose code is ignored in the-recomputation of the real arrow for a1.-Mutually recursive bindings will be a bit more tricky.--> transCmd s p (LetCmd (VarDecl loc n c1) c2) =->	letCmd [VarDecl loc n a1] (transCmd s' p c2)->	where	(_, a1) = transTrimCmd s' c1->		s' = s { cmdVars = Map.insert n a0 (cmdVars s) }->		s0 = s { cmdVars = Map.insert n returnA (cmdVars s) }->		a0 = transCmd s0 p c1	-- hackety hack-> transCmd s p (CmdVar n) =->	arr (anonArgs a) (input s) p e >>> arrowExp (HsVar (UnQual n))->	where	Just a = Map.lookup n (cmdVars s)->		e = expTuple (context a)--Like TransCmd, but use the minimal input pattern.  The first component-of the result is the matching expression to build this input.-That is, the result is (e, proc p' -> c) with the minimal p' such that--	proc p -> c = arr (first^n (p -> e)) >>> (proc p' -> c)--where n is the number of anonymous arguments taken by c.--> transTrimCmd :: TransState -> Cmd -> (HsExp, Arrow)-> transTrimCmd s c = (expTuple (context a), a)->	where	a = transCmd s (patternTuple (context a)) c--> transDo :: TransState -> HsPat -> [Stmt] -> Cmd -> Arrow-> transDo s p [] c =->	transCmd s p c-> transDo s p (Generator _ pg cg:ss) c =->	if isEmptyTuple u then->		transCmd s p cg >>> transDo s' pg ss c->	else->		arr 0 (input s) p (pair eg (expTuple u)) >>> first ag u >>> a->	where	(s', pg') = addVars s pg->		a = bind (freeVars pg)->			(transDo s' (pairP pg' (patternTuple u)) ss c)->		u = context a->		(eg, ag) = transTrimCmd s cg-> transDo s p (LetStmt decls:ss) c =->	transCmd s p (Let decls (Do ss c))-> transDo s p (RecStmt rss:ss) c =->	bind defined->		(loop (transDo s' (pairP p (irrPat (patternTuple feedback)))->			rss'->			(returnCmd (pair output (expTuple feedback)))->		      ) >>> a)->	where	defined = definedVars rss->		(s', rss') = addVars s rss->		(output, a) = transTrimCmd s' (Do ss c)->		feedback = context (transDo s' p rss'->				(returnCmd (foldr pair output $ map (HsVar . UnQual) $ Set.toList defined)))->			`intersectTuple` defined-> transDo s p (LetCmdStmt vdecl:ss) c =->	transCmd s p (LetCmd vdecl (Do ss c))--The set of variables defined by a list of statements in a rec.--> instance DefinedVars Stmt where->	definedVars (Generator _ p _) = freeVars p->	definedVars (LetStmt decls) = definedVars decls->	definedVars (RecStmt stmts) = definedVars stmts->	definedVars (LetCmdStmt _vdecl) = Set.empty--> instance AddVars Stmt where->	addVars s (Generator loc p c) =->		(s', Generator loc p' c)->		where	(s', p') = addVars s p->	addVars s (LetStmt decls) =->		(s', LetStmt decls')->		where	(s', decls') = addVars s decls->	addVars s (RecStmt stmts) =->		(s', RecStmt stmts')->		where	(s', stmts') = addVars s stmts->	addVars s stmt@(LetCmdStmt _vdecl) =->		(s, stmt)--Translation of case commands uses a right-nested sum,-corresponding to the right-associativity of (|||).-(In future: use a balanced sum.)--The state kept while traversing the expression is-	(count of rhss, rhss in reverse order)--> transCase :: TransState -> HsPat -> HsExp -> [Alt] -> Arrow-> transCase s p e as =->	arr 0 (input s) p (HsCase e as') >>> foldr1 (|||) (reverse cases)->	where	(as', (ncases, cases)) =->			runState (mapM (transAlt s) as) (0, [])->		transAlt s (Alt loc p gas decls) = do->			let	(s', p') = addVars s p->				(s'', decls') = addVars s' decls->			gas' <- transGuardedAlts s'' gas->			return (HsAlt loc p' gas' decls')->		transGuardedAlts s (UnGuardedAlt c) = do->			body <- newAlt s c->			return (HsUnGuardedAlt body)->		transGuardedAlts s (GuardedAlts gas) = do->			gas' <- mapM (transGuardedAlt s) gas->			return (HsGuardedAlts gas')->		transGuardedAlt s (GuardedAlt loc e c) = do->			body <- newAlt s c->			return (HsGuardedAlt loc e body)->		newAlt s c = do->			let (e, a) = transTrimCmd s c->			(n, as) <- get->			put (n+1, a:as)->			return (label n e)->		label n e = times n right->				(if n < ncases-1 then left e else e)
+ src/Control/Arrow/Notation.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedLists       #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++module Control.Arrow.Notation+  ( translateModule+  , translateExp+  ) where++import           Data.Generics.Uniplate.Data+import           Language.Haskell.Exts       as H hiding (Tuple)++import           ArrSyn+import           Utils++translateModule :: Module SrcSpanInfo -> Module SrcSpanInfo+translateModule = transformBi translateExp++translateExp :: Exp SrcSpanInfo -> Exp SrcSpanInfo+translateExp (Proc _ pat exp) =+  getSrcSpanInfo <$> ArrSyn.translate (fmap S pat) (fmap S exp)+translateExp other = other
src/Control/Arrow/QuasiQuoter.hs view
@@ -1,24 +1,17 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE MultiParamTypeClasses #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TemplateHaskell #-} module Control.Arrow.QuasiQuoter   ( proc-  , parseModuleWithMode   ) where -import Data.Maybe+import Control.Arrow.Notation+import Data.List -import Language.Haskell.TH+import Language.Haskell.Exts as Exts hiding (Exp, Loc)+import Language.Haskell.Meta+import Language.Haskell.TH (Exp, Q, Loc(..), location ) import Language.Haskell.TH.Quote -import Language.Haskell.ParseMonad-import Language.Haskell.Syntax-import Language.Haskell.Pretty--import Parser- import Text.Printf  -- | A quasiquoter for arrow notation.@@ -38,136 +31,27 @@   }  quote :: String -> Q Exp-quote inp =-  case parseProc ("proc " ++ inp) of-    ParseOk proc -> tr proc+quote = quoteEx defaultParseMode { extensions = defaultExtensions }++quoteEx :: ParseMode -> String -> Q Exp+quoteEx mode inp =+  case parseExpWithMode mode ("proc " ++ inp) of+    ParseOk proc -> return $ toExp $ translateExp proc     ParseFailed loc err -> do       Loc{..} <- location       error $ printf "%s:%d:%d: %s" loc_filename                                    (fst loc_start + srcLine loc - 1)                                    (snd loc_start + srcColumn loc - 1)                                    err--class Translate hs th | hs -> th where-  tr :: hs -> Q th--trAll xx = traverse tr xx--instance Translate HsExp Exp where-  tr (HsVar name) = VarE <$> tr name-  tr (HsCon (Special HsUnitCon)) = [|()|]-  tr (HsCon (Special HsListCon)) = [|[]|]-  tr (HsCon (Special HsCons)) = [| (:) |]-  tr (HsCon (Special (HsTupleCon 2))) = [| (,) |]-  tr (HsCon (Special (HsTupleCon 3))) = [| (,,) |]-  tr (HsCon (Special (HsTupleCon 4))) = [| (,,,) |]-  tr (HsCon name) = ConE <$> tr name-  tr (HsLit lit)  = LitE <$> tr lit-  tr (HsInfixApp a op b) =-    InfixE <$> (Just <$> tr a) <*> tr op <*> (Just <$> tr b)-  tr (HsApp a b) = AppE <$> tr a <*> tr b-  tr (HsLambda _ pats e) = LamE <$> trAll pats <*> tr e-  tr (HsLet decs e) = LetE <$> trAll decs <*> tr e-  tr (HsIf c t e) = CondE <$> tr c <*> tr t <*> tr e-  tr (HsCase e aa) = CaseE <$> tr e <*> trAll aa-  tr (HsDo ss) = DoE <$> trAll ss-  tr (HsTuple ee) = TupE <$> trAll ee-  tr (HsList ee) = ListE <$> trAll ee-  tr (HsParen e) = ParensE <$> tr e-  tr (HsLeftSection  e op) = InfixE <$> (Just <$> tr e) <*> tr op <*> pure Nothing-  tr (HsRightSection op e) = InfixE <$> pure Nothing    <*> tr op <*> (Just <$> tr e)-  tr (HsRecConstr n ff) = RecConE <$> tr n <*> trAll ff-  tr (HsRecUpdate e ff) = RecUpdE <$> tr e <*> trAll ff-  tr (HsEnumFrom e) = ArithSeqE . FromR <$> tr e-  tr (HsEnumFromThen f t) = ArithSeqE <$> (FromThenR <$> tr f <*> tr t)-  tr (HsEnumFromThenTo f t to) = ArithSeqE <$> (FromThenToR <$> tr f <*> tr t <*> tr to)-  tr (HsEnumFromTo f to) = ArithSeqE <$> (FromToR <$> tr f <*> tr to)-  tr (HsListComp e ss) = (\e ss -> CompE (ss ++ [NoBindS e])) <$> tr e <*> trAll ss-  tr (HsExpTypeSig _ e _) = tr e-  tr HsNegApp{} = error "not applicable"-  tr HsWildCard = error "not applicable"-  tr HsAsPat{} = error "not applicable"-  tr HsIrrPat{} = error "not applicable"--instance Translate HsDecl Dec where-  tr (HsFunBind mm@(HsMatch _ n _ _ _ : _)) = FunD <$> (mkName <$> tr n) <*> trAll mm-  tr (HsPatBind _ p r dd) = ValD <$> tr p <*> tr r <*> trAll dd-  tr _ = error "not implemented: HsDecl"--instance Translate HsMatch Clause where-  tr (HsMatch _ _ pats rhs decls) = Clause <$> trAll pats <*> tr rhs <*> trAll decls--instance Translate HsAlt Match where-  tr (HsAlt _ p aa dd ) = Match <$> tr p <*> tr aa <*> trAll dd--instance Translate HsGuardedAlts Body where-  tr (HsGuardedAlts aa) = GuardedB <$> trAll aa-  tr (HsUnGuardedAlt e) = NormalB <$> tr e--instance Translate HsGuardedAlt (Guard,Exp) where-  tr (HsGuardedAlt _ e e') = (,) <$> (NormalG <$> tr e) <*> tr e'--instance Translate HsStmt Stmt where-  tr (HsGenerator _ p e) = BindS <$> tr p <*> tr e-  tr (HsQualifier e) = NoBindS <$> tr e-  tr (HsLetStmt dd)  = LetS <$> trAll dd--instance Translate HsFieldUpdate FieldExp where-  tr (HsFieldUpdate n e) = (,) <$> tr n <*> tr e--instance Translate HsRhs Body where-  tr (HsUnGuardedRhs e) = NormalB <$> tr e-  tr (HsGuardedRhss gg) = GuardedB <$> trAll gg--instance Translate HsGuardedRhs (Guard,Exp) where-  tr (HsGuardedRhs _ e e') = (,) . NormalG <$> tr e <*> tr e'--instance Translate HsLiteral Lit where-  tr (HsChar c) = pure $ CharL c-  tr (HsString s) = pure $ StringL s-  tr (HsInt i) = pure $ IntPrimL i-  tr (HsFrac f) = pure $ RationalL f-  tr (HsCharPrim c) = pure $ CharPrimL c-  tr (HsIntPrim c) = pure $ IntPrimL c-  tr (HsStringPrim s) = pure $ StringL s-  tr (HsFloatPrim s) = pure $ FloatPrimL s-  tr (HsDoublePrim x) = pure $ DoublePrimL x--instance Translate HsQOp Exp where-  tr (HsQVarOp n) = VarE <$> tr n-  tr (HsQConOp n) = VarE <$> tr n--instance Translate HsPat Pat where-  tr (HsPVar n) = VarP . mkName <$> tr n-  tr (HsPLit l) = LitP <$> tr l-  tr (HsPInfixApp p1 n p2) = InfixP <$> tr p1 <*> tr n <*> tr p2-  tr (HsPApp n pats) = ConP <$> tr n <*> trAll pats-  tr (HsPTuple pats) = TupP <$> trAll pats-  tr (HsPList pats)  = ListP <$> trAll pats-  tr (HsPParen pat)  = ParensP <$> tr pat-  tr (HsPRec n pats) = RecP <$> tr n <*> trAll pats-  tr  HsPWildCard    = return WildP-  tr (HsPIrrPat pat) = TildeP <$> tr pat-  tr HsPNeg{} = error "not implemented: HsPNeg"-  tr HsPAsPat{} = error "not implemented: HsPAsPat"--instance Translate HsPatField FieldPat where-  tr (HsPFieldPat n pat) = (,) <$> tr n <*> tr pat--instance Translate HsQName Name where-  tr (UnQual n) = do-    n <- tr n-    return $ mkName n-  tr (Qual (Module m) n) = do-    n <- tr n-    fromMaybe (error $ printf "Not found: %s.%s" m n) <$> lookupValueName (m ++ "." ++ n)-  tr (Special (HsTupleCon 2)) = error "unhandled Special tuplecon id"-  tr (Special HsUnitCon) =  error "unhandled special unitcon id"-  tr (Special HsListCon) = error "unhandled special listcon id"-  tr (Special HsFunCon) = error "unhandled special funcon id"-  tr (Special HsCons) = error "unhandled special cons id"-+defaultExtensions :: [Extension]+defaultExtensions = [e | e@EnableExtension{} <- knownExtensions] \\ map EnableExtension badExtensions -instance Translate HsName [Char] where-  tr (HsSymbol s) = return s-  tr (HsIdent  n) = return n+badExtensions :: [KnownExtension]+badExtensions =+    [TransformListComp -- steals the group keyword+    ,XmlSyntax, RegularPatterns -- steals a-b+    ,UnboxedTuples -- breaks (#) lens operator+    ,QuasiQuotes -- breaks [x| ...], making whitespace free list comps break+    ,DoRec, RecursiveDo -- breaks rec+    ,TypeApplications -- HSE fails on @ patterns+    ]
− src/Lexer.hs
@@ -1,564 +0,0 @@--- #hide--------------------------------------------------------------------------------- |--- Module      :  Lexer--- Copyright   :  (c) The GHC Team, 1997-2000--- License     :  BSD-style (see the file libraries/base/LICENSE)--- --- Maintainer  :  libraries@haskell.org--- Stability   :  experimental--- Portability :  portable------ Lexer for Haskell.------------------------------------------------------------------------------------- ToDo: Introduce different tokens for decimal, octal and hexadecimal (?)--- ToDo: FloatTok should have three parts (integer part, fraction, exponent) (?)--- ToDo: Use a lexical analyser generator (lx?)--module Lexer (Token(..), lexer) where--import Language.Haskell.ParseMonad--import Data.Char	(isAlpha, isLower, isUpper, toLower,-			 isDigit, isHexDigit, isOctDigit, isSpace,-			 ord, chr, digitToInt)-import Data.Ratio--data Token-        = VarId String-        | QVarId (String,String)-	| ConId String-        | QConId (String,String)-        | VarSym String-        | ConSym String-        | QVarSym (String,String)-        | QConSym (String,String)-	| IntTok Integer-	| FloatTok Rational-	| Character Char-        | StringTok String---- Symbols--	| LeftParen-	| RightParen-	| SemiColon-        | LeftCurly-        | RightCurly-        | VRightCurly			-- a virtual close brace-        | LeftSquare-        | RightSquare-	| Comma-        | Underscore-        | BackQuote---- Reserved operators--	| DotDot-	| Colon-	| DoubleColon-	| Equals-	| Backslash-	| Bar-	| LeftArrow-	| RightArrow-	| At-	| Tilde-	| DoubleArrow-	| Minus-	| Exclamation-	| LeftArrowTail		-- added for arrows-	| RightArrowTail	-- added for arrows-	| LeftArrowDTail	-- added for arrows-	| RightArrowDTail	-- added for arrows-	| LeftBanana		-- added for arrows-	| RightBanana		-- added for arrows---- Reserved Ids--	| KW_Case-	| KW_Class-	| KW_Data-	| KW_Default-	| KW_Deriving-	| KW_Do-	| KW_Else-	| KW_Foreign-	| KW_If-	| KW_Import-	| KW_In-	| KW_Infix-	| KW_InfixL-	| KW_InfixR-	| KW_Instance-	| KW_Let-	| KW_Module-	| KW_NewType-	| KW_Of-	| KW_Then-	| KW_Type-	| KW_Where---- Special Ids--	| KW_As-	| KW_Export-	| KW_Hiding-	| KW_Qualified-	| KW_Safe-	| KW_Unsafe-	| KW_Proc		-- added for arrows-	| KW_Rec		-- added for arrows-	| KW_Form		-- added for arrows-	| KW_Cmd		-- added for arrows--        | EOF-        deriving (Eq,Show)--reserved_ops :: [(String,Token)]-reserved_ops = [- ( "..", DotDot ),- ( ":",  Colon ),- ( "::", DoubleColon ),- ( "=",  Equals ),- ( "\\", Backslash ),- ( "|",  Bar ),- ( "<-", LeftArrow ),- ( "->", RightArrow ),- ( "@",  At ),- ( "~",  Tilde ),- ( "=>", DoubleArrow ),- ( "-<", LeftArrowTail ),	-- added for arrows- ( ">-", RightArrowTail ),	-- added for arrows- ( "-<<", LeftArrowDTail ),	-- added for arrows- ( ">>-", RightArrowDTail ),	-- added for arrows- ( "\\<", Backslash )		-- added for arrows- ]--special_varops :: [(String,Token)]-special_varops = [- ( "-",  Minus ),			--ToDo: shouldn't be here- ( "!",  Exclamation )		--ditto- ]--reserved_ids :: [(String,Token)]-reserved_ids = [- ( "_",         Underscore ),- ( "case",      KW_Case ),- ( "class",     KW_Class ),- ( "cmd",	KW_Cmd ),	-- added for arrows- ( "data",      KW_Data ),- ( "default",   KW_Default ),- ( "deriving",  KW_Deriving ),- ( "do",        KW_Do ),- ( "else",      KW_Else ),- ( "foreign",	KW_Foreign ),- ( "if",    	KW_If ),- ( "import",    KW_Import ),- ( "in", 	KW_In ),- ( "infix", 	KW_Infix ),- ( "infixl", 	KW_InfixL ),- ( "infixr", 	KW_InfixR ),- ( "instance",  KW_Instance ),- ( "let", 	KW_Let ),- ( "module", 	KW_Module ),- ( "newtype",   KW_NewType ),- ( "of", 	KW_Of ),- ( "proc",	KW_Proc ),	-- added for arrows- ( "rec",	KW_Rec ),	-- added for arrows- ( "then", 	KW_Then ),- ( "type", 	KW_Type ),- ( "where", 	KW_Where )- ]--special_varids :: [(String,Token)]-special_varids = [- ( "as", 	KW_As ),- ( "export", 	KW_Export ),- ( "hiding", 	KW_Hiding ),- ( "qualified", KW_Qualified ),- ( "safe",	KW_Safe ),- ( "unsafe", 	KW_Unsafe )- ]--isIdent, isSymbol :: Char -> Bool-isIdent  c = isAlpha c || isDigit c || c == '\'' || c == '_'-isSymbol c = elem c ":!#$%&*+./<=>?@\\^|-~"--matchChar :: Char -> String -> Lex a ()-matchChar c msg = do-	s <- getInput-	if null s || head s /= c then fail msg else discard 1---- The top-level lexer.--- We need to know whether we are at the beginning of the line to decide--- whether to insert layout tokens.--lexer :: (Token -> P a) -> P a-lexer = runL $ do-	bol <- checkBOL-	bol <- lexWhiteSpace bol-	startToken-	if bol then lexBOL else lexToken--lexWhiteSpace :: Bool -> Lex a Bool-lexWhiteSpace bol = do-	s <- getInput-	case s of-	    '{':'-':_ -> do-		discard 2-		bol <- lexNestedComment bol-		lexWhiteSpace bol-	    '-':'-':rest | all (== '-') (takeWhile isSymbol rest) -> do-		lexWhile (== '-')-		lexWhile (/= '\n')-		s' <- getInput-		case s' of-		    [] -> fail "Unterminated end-of-line comment"-		    _ -> do-			lexNewline-			lexWhiteSpace True-	    '\n':_ -> do-		lexNewline-		lexWhiteSpace True-	    '\t':_ -> do-		lexTab-		lexWhiteSpace bol-	    c:_ | isSpace c -> do-		discard 1-		lexWhiteSpace bol-	    _ -> return bol--lexNestedComment :: Bool -> Lex a Bool-lexNestedComment bol = do-	s <- getInput-	case s of-	    '-':'}':_ -> discard 2 >> return bol-	    '{':'-':_ -> do-		discard 2-		bol <- lexNestedComment bol	-- rest of the subcomment-		lexNestedComment bol		-- rest of this comment-	    '\t':_    -> lexTab >> lexNestedComment bol-	    '\n':_    -> lexNewline >> lexNestedComment True-	    _:_       -> discard 1 >> lexNestedComment bol-	    []        -> fail "Unterminated nested comment"---- When we are lexing the first token of a line, check whether we need to--- insert virtual semicolons or close braces due to layout.--lexBOL :: Lex a Token-lexBOL = do-	pos <- getOffside-	case pos of-	    LT -> do-                -- trace "layout: inserting '}'\n" $-        	-- Set col to 0, indicating that we're still at the-        	-- beginning of the line, in case we need a semi-colon too.-        	-- Also pop the context here, so that we don't insert-        	-- another close brace before the parser can pop it.-		setBOL-		popContextL "lexBOL"-		return VRightCurly-	    EQ ->-                -- trace "layout: inserting ';'\n" $-		return SemiColon-	    GT ->-		lexToken--lexToken :: Lex a Token-lexToken = do-    s <- getInput-    case s of-        [] -> return EOF--	'0':c:d:_ | toLower c == 'o' && isOctDigit d -> do-			discard 2-			n <- lexOctal-			return (IntTok n)-		  | toLower c == 'x' && isHexDigit d -> do-			discard 2-			n <- lexHexadecimal-			return (IntTok n)--	'(':'|':c:_ | not (isSymbol c) -> do-	    discard 2-	    return LeftBanana--	'|':')':_ -> do-	    discard 2-	    return RightBanana--	c:_ | isDigit c -> lexDecimalOrFloat--	    | isUpper c -> lexConIdOrQual ""--	    | isLower c || c == '_' -> do-		ident <- lexWhile isIdent-		return $ case lookup ident (reserved_ids ++ special_varids) of-			Just keyword -> keyword-			Nothing -> VarId ident--	    | isSymbol c -> do-		sym <- lexWhile isSymbol-		return $ case lookup sym (reserved_ops ++ special_varops) of-			Just t  -> t-			Nothing -> case c of-			    ':' -> ConSym sym-			    _   -> VarSym sym--	    | otherwise -> do-		discard 1-		case c of--		    -- First the special symbols-		    '(' ->  return LeftParen-		    ')' ->  return RightParen-		    ',' ->  return Comma-		    ';' ->  return SemiColon-		    '[' ->  return LeftSquare-		    ']' ->  return RightSquare-		    '`' ->  return BackQuote-		    '{' -> do-			    pushContextL NoLayout-			    return LeftCurly-		    '}' -> do-			    popContextL "lexToken"-			    return RightCurly--		    '\'' -> do-			    c2 <- lexChar-			    matchChar '\'' "Improperly terminated character constant"-			    return (Character c2)--		    '"' ->  lexString--		    _ ->    fail ("Illegal character \'" ++ show c ++ "\'\n")--lexDecimalOrFloat :: Lex a Token-lexDecimalOrFloat = do-	ds <- lexWhile isDigit-	rest <- getInput-	case rest of-	    ('.':d:_) | isDigit d -> do-		discard 1-		frac <- lexWhile isDigit-		let num = parseInteger 10 (ds ++ frac)-		    decimals = toInteger (length frac)-		exponent <- do-			rest2 <- getInput-			case rest2 of-			    'e':_ -> lexExponent-			    'E':_ -> lexExponent-			    _     -> return 0-		return (FloatTok ((num%1) * 10^^(exponent - decimals)))-	    e:_ | toLower e == 'e' -> do-		exponent <- lexExponent-		return (FloatTok ((parseInteger 10 ds%1) * 10^^exponent))-	    _ -> return (IntTok (parseInteger 10 ds))--    where-	lexExponent :: Lex a Integer-	lexExponent = do-		discard 1	-- 'e' or 'E'-		r <- getInput-		case r of-		    '+':d:_ | isDigit d -> do-			discard 1-			lexDecimal-		    '-':d:_ | isDigit d -> do-			discard 1-			n <- lexDecimal-			return (negate n)-		    d:_ | isDigit d -> lexDecimal-		    _ -> fail "Float with missing exponent"--lexConIdOrQual :: String -> Lex a Token-lexConIdOrQual qual = do-	con <- lexWhile isIdent-	let conid | null qual = ConId con-		  | otherwise = QConId (qual,con)-	    qual' | null qual = con-		  | otherwise = qual ++ '.':con-	just_a_conid <- alternative (return conid)-	rest <- getInput-	case rest of-	  '.':c:_-	     | isLower c || c == '_' -> do	-- qualified varid?-		discard 1-		ident <- lexWhile isIdent-		case lookup ident reserved_ids of-		   -- cannot qualify a reserved word-		   Just _  -> just_a_conid-		   Nothing -> return (QVarId (qual', ident))--	     | isUpper c -> do		-- qualified conid?-		discard 1-		lexConIdOrQual qual'--	     | isSymbol c -> do	-- qualified symbol?-		discard 1-		sym <- lexWhile isSymbol-		case lookup sym reserved_ops of-		    -- cannot qualify a reserved operator-		    Just _  -> just_a_conid-		    Nothing -> return $ case c of-			':' -> QConSym (qual', sym)-			_   -> QVarSym (qual', sym)--	  _ ->	return conid -- not a qualified thing--lexChar :: Lex a Char-lexChar = do-	r <- getInput-	case r of-		'\\':_	-> lexEscape-		c:_	-> discard 1 >> return c-		[]	-> fail "Incomplete character constant"--lexString :: Lex a Token-lexString = loop ""-    where-	loop s = do-		r <- getInput-		case r of-		    '\\':'&':_ -> do-				discard 2-				loop s-		    '\\':c:_ | isSpace c -> do-				discard 1-				lexWhiteChars-				matchChar '\\' "Illegal character in string gap"-				loop s-			     | otherwise -> do-				ce <- lexEscape-				loop (ce:s)-		    '"':_ -> do-				discard 1-				return (StringTok (reverse s))-		    c:_ -> do-				discard 1-				loop (c:s)-		    [] ->	fail "Improperly terminated string"--	lexWhiteChars :: Lex a ()-	lexWhiteChars = do-		s <- getInput-		case s of-		    '\n':_ -> do-			lexNewline-			lexWhiteChars-		    '\t':_ -> do-			lexTab-			lexWhiteChars-		    c:_ | isSpace c -> do-			discard 1-			lexWhiteChars-		    _ -> return ()--lexEscape :: Lex a Char-lexEscape = do-	discard 1-	r <- getInput-	case r of---- Production charesc from section B.2 (Note: \& is handled by caller)--		'a':_		-> discard 1 >> return '\a'-		'b':_		-> discard 1 >> return '\b'-		'f':_		-> discard 1 >> return '\f'-		'n':_		-> discard 1 >> return '\n'-		'r':_		-> discard 1 >> return '\r'-		't':_		-> discard 1 >> return '\t'-		'v':_		-> discard 1 >> return '\v'-		'\\':_		-> discard 1 >> return '\\'-		'"':_		-> discard 1 >> return '\"'-		'\'':_		-> discard 1 >> return '\''---- Production ascii from section B.2--		'^':c:_		-> discard 2 >> cntrl c-		'N':'U':'L':_	-> discard 3 >> return '\NUL'-		'S':'O':'H':_	-> discard 3 >> return '\SOH'-		'S':'T':'X':_	-> discard 3 >> return '\STX'-		'E':'T':'X':_	-> discard 3 >> return '\ETX'-		'E':'O':'T':_	-> discard 3 >> return '\EOT'-		'E':'N':'Q':_	-> discard 3 >> return '\ENQ'-		'A':'C':'K':_	-> discard 3 >> return '\ACK'-		'B':'E':'L':_	-> discard 3 >> return '\BEL'-		'B':'S':_	-> discard 2 >> return '\BS'-		'H':'T':_	-> discard 2 >> return '\HT'-		'L':'F':_	-> discard 2 >> return '\LF'-		'V':'T':_	-> discard 2 >> return '\VT'-		'F':'F':_	-> discard 2 >> return '\FF'-		'C':'R':_	-> discard 2 >> return '\CR'-		'S':'O':_	-> discard 2 >> return '\SO'-		'S':'I':_	-> discard 2 >> return '\SI'-		'D':'L':'E':_	-> discard 3 >> return '\DLE'-		'D':'C':'1':_	-> discard 3 >> return '\DC1'-		'D':'C':'2':_	-> discard 3 >> return '\DC2'-		'D':'C':'3':_	-> discard 3 >> return '\DC3'-		'D':'C':'4':_	-> discard 3 >> return '\DC4'-		'N':'A':'K':_	-> discard 3 >> return '\NAK'-		'S':'Y':'N':_	-> discard 3 >> return '\SYN'-		'E':'T':'B':_	-> discard 3 >> return '\ETB'-		'C':'A':'N':_	-> discard 3 >> return '\CAN'-		'E':'M':_	-> discard 2 >> return '\EM'-		'S':'U':'B':_	-> discard 3 >> return '\SUB'-		'E':'S':'C':_	-> discard 3 >> return '\ESC'-		'F':'S':_	-> discard 2 >> return '\FS'-		'G':'S':_	-> discard 2 >> return '\GS'-		'R':'S':_	-> discard 2 >> return '\RS'-		'U':'S':_	-> discard 2 >> return '\US'-		'S':'P':_	-> discard 2 >> return '\SP'-		'D':'E':'L':_	-> discard 3 >> return '\DEL'---- Escaped numbers--		'o':c:_ | isOctDigit c -> do-					discard 1-					n <- lexOctal-					checkChar n-		'x':c:_ | isHexDigit c -> do-					discard 1-					n <- lexHexadecimal-					checkChar n-		c:_ | isDigit c -> do-					n <- lexDecimal-					checkChar n--		_		-> fail "Illegal escape sequence"--    where-	checkChar n | n <= 0x10FFFF = return (chr (fromInteger n))-	checkChar _		    = fail "Character constant out of range"---- Production cntrl from section B.2--	cntrl :: Char -> Lex a Char-	cntrl c | c >= '@' && c <= '_' = return (chr (ord c - ord '@'))-	cntrl _                        = fail "Illegal control character"---- assumes at least one octal digit-lexOctal :: Lex a Integer-lexOctal = do-	ds <- lexWhile isOctDigit-	return (parseInteger 8 ds)---- assumes at least one hexadecimal digit-lexHexadecimal :: Lex a Integer-lexHexadecimal = do-	ds <- lexWhile isHexDigit-	return (parseInteger 16 ds)---- assumes at least one decimal digit-lexDecimal :: Lex a Integer-lexDecimal = do-	ds <- lexWhile isDigit-	return (parseInteger 10 ds)---- Stolen from Hugs's Prelude-parseInteger :: Integer -> String -> Integer-parseInteger radix ds =-	foldl1 (\n d -> n * radix + d) (map (toInteger . digitToInt) ds)
− src/Parser.ly
@@ -1,997 +0,0 @@-> {-> ------------------------------------------------------------------------------> -- |-> -- Module      :  Parser-> -- Copyright   :  (c) Simon Marlow, Sven Panne 1997-2000-> -- License     :  BSD-style (see the file libraries/base/LICENSE)-> ---> -- Maintainer  :  libraries@haskell.org-> -- Stability   :  experimental-> -- Portability :  portable-> ---> -- Haskell parser.-> ---> ------------------------------------------------------------------------------>-> module Parser (->		parseModule, parseModuleWithMode,->		ParseMode(..), defaultParseMode, ParseResult(..),->   parseProc->   ) where-> -> import Language.Haskell.Syntax-> import Language.Haskell.ParseMonad-> import Lexer-> import Language.Haskell.ParseUtils-> -> import qualified ArrSyn		-- added for arrows-> }--ToDo: Check exactly which names must be qualified with Prelude (commas and friends)-ToDo: Inst (MPCs?)-ToDo: Polish constr a bit-ToDo: Ugly: exp0b is used for lhs, pat, exp0, ...-ToDo: Differentiate between record updates and labeled construction.--------------------------------------------------------------------------------Conflicts: 2 shift/reduce--2 for ambiguity in 'case x of y | let z = y in z :: Bool -> b'-	(don't know whether to reduce 'Bool' as a btype or shift the '->'.-	 Similarly lambda and if.  The default resolution in favour of the-	 shift means that a guard can never end with a type signature.-	 In mitigation: it's a rare case and no Haskell implementation-	 allows these, because it would require unbounded lookahead.)-	There are 2 conflicts rather than one because contexts are parsed-	as btypes (cf ctype).---------------------------------------------------------------------------------> %token->	VARID 	 { VarId $$ }->	QVARID 	 { QVarId $$ }->	CONID	 { ConId $$ }->	QCONID   { QConId $$ }->	VARSYM	 { VarSym $$ }->	CONSYM	 { ConSym $$ }->	QVARSYM	 { QVarSym $$ }->	QCONSYM  { QConSym $$ }->	INT	 { IntTok $$ }->	RATIONAL { FloatTok $$ }->	CHAR	 { Character $$ }->	STRING   { StringTok $$ }--Symbols-->	'('	{ LeftParen }->	')'	{ RightParen }->	';'	{ SemiColon }->	'{'	{ LeftCurly }->	'}'	{ RightCurly }->	vccurly { VRightCurly }			-- a virtual close brace->	'['	{ LeftSquare }->	']'	{ RightSquare }->  	','	{ Comma }->	'_'	{ Underscore }->	'`'	{ BackQuote }--Reserved operators-->	'..'	{ DotDot }->	':'	{ Colon }->	'::'	{ DoubleColon }->	'='	{ Equals }->	'\\'	{ Backslash }->	'|'	{ Bar }->	'<-'	{ LeftArrow }->	'->'	{ RightArrow }->	'@'	{ At }->	'~'	{ Tilde }->	'=>'	{ DoubleArrow }->	'-<'	{ LeftArrowTail }		-- added for arrows->	'>-'	{ RightArrowTail }		-- added for arrows->	'-<<'	{ LeftArrowDTail }		-- added for arrows->	'>>-'	{ RightArrowDTail }		-- added for arrows->	'(|'	{ LeftBanana }			-- added for arrows->	'|)'	{ RightBanana }			-- added for arrows->	'-'	{ Minus }->	'!'	{ Exclamation }--Reserved Ids-->	'case'		{ KW_Case }->	'class'		{ KW_Class }->	'data'		{ KW_Data }->	'default'	{ KW_Default }->	'deriving'	{ KW_Deriving }->	'do'		{ KW_Do }->	'else'		{ KW_Else }->	'foreign'	{ KW_Foreign }->	'if'		{ KW_If }->	'import'	{ KW_Import }->	'in'		{ KW_In }->	'infix'		{ KW_Infix }->	'infixl'	{ KW_InfixL }->	'infixr'	{ KW_InfixR }->	'instance'	{ KW_Instance }->	'let'		{ KW_Let }->	'module'	{ KW_Module }->	'newtype'	{ KW_NewType }->	'of'		{ KW_Of }->	'then'		{ KW_Then }->	'type'		{ KW_Type }->	'where'		{ KW_Where }--Special Ids-->	'as'		{ KW_As }->	'export'	{ KW_Export }->	'hiding'	{ KW_Hiding }->	'qualified'	{ KW_Qualified }->	'safe'		{ KW_Safe }->	'unsafe'	{ KW_Unsafe }->	'proc'		{ KW_Proc }		-- added for arrows->	'rec'		{ KW_Rec }		-- added for arrows->	'cmd'		{ KW_Cmd }		-- added for arrows--> %monad { P }-> %lexer { lexer } { EOF }-> %name parse module-> %name parseProcExp procExp-> %tokentype { Token }-> %%--------------------------------------------------------------------------------Module Header--> module :: { HsModule }->	: srcloc 'module' modid maybeexports 'where' body->		{ HsModule $1 $3 $4 (fst $6) (snd $6) }->	| srcloc body->		{ HsModule $1 main_mod (Just [HsEVar (UnQual main_name)])->							(fst $2) (snd $2) }--> body :: { ([HsImportDecl],[HsDecl]) }->	: '{'  bodyaux '}'			{ $2 }->	| open bodyaux close			{ $2 }--> bodyaux :: { ([HsImportDecl],[HsDecl]) }->	: optsemis impdecls semis topdecls	{ (reverse $2, $4) }->	| optsemis                topdecls	{ ([], $2) }->	| optsemis impdecls optsemis		{ (reverse $2, []) }->	| optsemis				{ ([], []) }--> semis :: { () }->	: optsemis ';'				{ () }--> optsemis :: { () }->	: semis					{ () }->	| {- empty -}				{ () }--------------------------------------------------------------------------------The Export List--> maybeexports :: { Maybe [HsExportSpec] }-> 	:  exports				{ Just $1 }-> 	|  {- empty -}				{ Nothing }--> exports :: { [HsExportSpec] }->	: '(' exportlist optcomma ')'		{ reverse $2 }->	| '(' optcomma ')'			{ [] }--> optcomma :: { () }->	: ','					{ () }->	| {- empty -}				{ () }--> exportlist :: { [HsExportSpec] }-> 	:  exportlist ',' export		{ $3 : $1 }-> 	|  export				{ [$1]  }--> export :: { HsExportSpec }-> 	:  qvar					{ HsEVar $1 }-> 	|  qtyconorcls				{ HsEAbs $1 }-> 	|  qtyconorcls '(' '..' ')'		{ HsEThingAll $1 }-> 	|  qtyconorcls '(' ')'		        { HsEThingWith $1 [] }->	|  qtyconorcls '(' cnames ')'		{ HsEThingWith $1 (reverse $3) }-> 	|  'module' modid			{ HsEModuleContents $2 }--------------------------------------------------------------------------------Import Declarations--> impdecls :: { [HsImportDecl] }->	: impdecls semis impdecl		{ $3 : $1 }->	| impdecl				{ [$1] }--> impdecl :: { HsImportDecl }->	: srcloc 'import' optqualified modid maybeas maybeimpspec->				{ HsImportDecl $1 $4 $3 $5 $6 }--> optqualified :: { Bool }->       : 'qualified'                           { True  }->       | {- empty -}				{ False }--> maybeas :: { Maybe Module }->       : 'as' modid                            { Just $2 }->       | {- empty -}				{ Nothing }---> maybeimpspec :: { Maybe (Bool, [HsImportSpec]) }->	: impspec				{ Just $1 }->	| {- empty -}				{ Nothing }--> impspec :: { (Bool, [HsImportSpec]) }->	: opthiding '(' importlist optcomma ')'	{ ($1, reverse $3) }->	| opthiding '(' optcomma ')'		{ ($1, []) }--> opthiding :: { Bool }->	: 'hiding'				{ True }->	| {- empty -}				{ False }--> importlist :: { [HsImportSpec] }-> 	:  importlist ',' importspec		{ $3 : $1 }-> 	|  importspec				{ [$1]  }--> importspec :: { HsImportSpec }-> 	:  var					{ HsIVar $1 }-> 	|  tyconorcls				{ HsIAbs $1 }-> 	|  tyconorcls '(' '..' ')'		{ HsIThingAll $1 }-> 	|  tyconorcls '(' ')'		        { HsIThingWith $1 [] }-> 	|  tyconorcls '(' cnames ')'		{ HsIThingWith $1 (reverse $3) }--> cnames :: { [HsCName] }-> 	:  cnames ',' cname			{ $3 : $1 }-> 	|  cname				{ [$1]  }--> cname :: { HsCName }->	:  var					{ HsVarName $1 }-> 	|  con					{ HsConName $1 }--------------------------------------------------------------------------------Fixity Declarations--> fixdecl :: { HsDecl }-> 	: srcloc infix prec ops			{ HsInfixDecl $1 $2 $3 (reverse $4) }--> prec :: { Int }->	: {- empty -}				{ 9 }->	| INT					{% checkPrec $1 }--> infix :: { HsAssoc }->	: 'infix'				{ HsAssocNone  }->	| 'infixl'				{ HsAssocLeft  }->	| 'infixr'				{ HsAssocRight }--> ops   :: { [HsOp] }->	: ops ',' op				{ $3 : $1 }->	| op					{ [$1] }--------------------------------------------------------------------------------Top-Level Declarations--Note: The report allows topdecls to be empty. This would result in another-shift/reduce-conflict, so we don't handle this case here, but in bodyaux.--> topdecls :: { [HsDecl] }->	: topdecls1 optsemis		{% checkRevDecls $1 }--> topdecls1 :: { [HsDecl] }->	: topdecls1 semis topdecl	{ $3 : $1 }->	| topdecl			{ [$1] }--> topdecl :: { HsDecl }->	: srcloc 'type' simpletype '=' type->			{ HsTypeDecl $1 (fst $3) (snd $3) $5 }->	| srcloc 'data' ctype '=' constrs deriving->			{% do { (cs,c,t) <- checkDataHeader $3;->				return (HsDataDecl $1 cs c t (reverse $5) $6) } }->	| srcloc 'newtype' ctype '=' constr deriving->			{% do { (cs,c,t) <- checkDataHeader $3;->				return (HsNewTypeDecl $1 cs c t $5 $6) } }->	| srcloc 'class' ctype optcbody->			{% do { (cs,c,vs) <- checkClassHeader $3;->				return (HsClassDecl $1 cs c vs $4) } }->	| srcloc 'instance' ctype optvaldefs->			{% do { (cs,c,ts) <- checkInstHeader $3;->				return (HsInstDecl $1 cs c ts $4) } }->	| srcloc 'default' '(' typelist ')'->			{ HsDefaultDecl $1 $4 }->	| foreigndecl	{ $1 }->       | decl		{ $1 }--> typelist :: { [HsType] }->	: types				{ reverse $1 }->	| type				{ [$1] }->	| {- empty -}			{ [] }--> decls :: { [HsDecl] }->	: optsemis decls1 optsemis	{% checkRevDecls $2 }->	| optsemis			{ [] }--> decls1 :: { [HsDecl] }->	: decls1 semis decl		{ $3 : $1 }->	| decl				{ [$1] }--> decl :: { HsDecl }->	: signdecl			{ $1 }->	| fixdecl			{ $1 }->	| valdef			{ $1 }--> decllist :: { [HsDecl] }->	: '{'  decls '}'		{ $2 }->	| open decls close		{ $2 }--> signdecl :: { HsDecl }->	: srcloc vars '::' ctype	{ HsTypeSig $1 (reverse $2) $4 }--ATTENTION: Dirty Hackery Ahead! If the second alternative of vars is var-instead of qvar, we get another shift/reduce-conflict. Consider the-following programs:--   { (+) :: ... }          only var-   { (+) x y  = ... }      could (incorrectly) be qvar--We re-use expressions for patterns, so a qvar would be allowed in patterns-instead of a var only (which would be correct). But deciding what the + is,-would require more lookahead. So let's check for ourselves...--> vars	:: { [HsName] }->	: vars ',' var			{ $3 : $1 }->	| qvar				{% do { n <- checkUnQual $1;->						return [n] } }--Foreign declarations-- calling conventions are uninterpreted-- external entities are not parsed-- special ids are not allowed as internal names--> foreigndecl :: { HsDecl }->	: srcloc 'foreign' 'import' VARID optsafety optentity fvar '::' type->			{ HsForeignImport $1 $4 $5 $6 $7 $9 }->	| srcloc 'foreign' 'export' VARID optentity fvar '::' type->			{ HsForeignExport $1 $4 $5 $6 $8 }--> optsafety :: { HsSafety }->	: 'safe'			{ HsSafe }->	| 'unsafe'			{ HsUnsafe }->	| {- empty -}			{ HsSafe }--> optentity :: { String }->	: STRING			{ $1 }->	| {- empty -}			{ "" }--> fvar :: { HsName }->	: VARID				{ HsIdent $1 }->	| '(' varsym ')'		{ $2 }--------------------------------------------------------------------------------Types--> type :: { HsType }->	: btype '->' type		{ HsTyFun $1 $3 }->	| btype				{ $1 }--> btype :: { HsType }->	: btype atype			{ HsTyApp $1 $2 }->	| atype				{ $1 }--> atype :: { HsType }->	: gtycon			{ HsTyCon $1 }->	| tyvar				{ HsTyVar $1 }->	| '(' types ')'			{ HsTyTuple (reverse $2) }->	| '[' type ']'			{ HsTyApp list_tycon $2 }->	| '(' type ')'			{ $2 }--> gtycon :: { HsQName }->	: qconid			{ $1 }->	| '(' ')'			{ unit_tycon_name }->	| '(' '->' ')'			{ fun_tycon_name }->	| '[' ']'			{ list_tycon_name }->	| '(' commas ')'		{ tuple_tycon_name $2 }---(Slightly edited) Comment from GHC's hsparser.y:-"context => type" vs  "type" is a problem, because you can't distinguish between--	foo :: (Baz a, Baz a)-	bar :: (Baz a, Baz a) => [a] -> [a] -> [a]--with one token of lookahead.  The HACK is to parse the context as a btype-(more specifically as a tuple type), then check that it has the right form-C a, or (C1 a, C2 b, ... Cn z) and convert it into a context.  Blaach!--> ctype :: { HsQualType }->	: context '=>' type		{ HsQualType $1 $3 }->	| type				{ HsQualType [] $1 }--> context :: { HsContext }->	: btype				{% checkContext $1 }--> types	:: { [HsType] }->	: types ',' type		{ $3 : $1 }->	| type  ',' type		{ [$3, $1] }--> simpletype :: { (HsName, [HsName]) }->	: tycon tyvars			{ ($1,reverse $2) }--> tyvars :: { [HsName] }->	: tyvars tyvar			{ $2 : $1 }->	| {- empty -}			{ [] }--------------------------------------------------------------------------------Datatype declarations--> constrs :: { [HsConDecl] }->	: constrs '|' constr		{ $3 : $1 }->	| constr			{ [$1] }--> constr :: { HsConDecl }->	: srcloc scontype		{ HsConDecl $1 (fst $2) (snd $2) }->	| srcloc sbtype conop sbtype	{ HsConDecl $1 $3 [$2,$4] }->	| srcloc con '{' '}'		{ HsRecDecl $1 $2 [] }->	| srcloc con '{' fielddecls '}' { HsRecDecl $1 $2 (reverse $4) }--> scontype :: { (HsName, [HsBangType]) }->	: btype				{% do { (c,ts) <- splitTyConApp $1;->						return (c,map HsUnBangedTy ts) } }->	| scontype1			{ $1 }--> scontype1 :: { (HsName, [HsBangType]) }->	: btype '!' atype		{% do { (c,ts) <- splitTyConApp $1;->						return (c,map HsUnBangedTy ts++->							[HsBangedTy $3]) } }->	| scontype1 satype		{ (fst $1, snd $1 ++ [$2] ) }--> satype :: { HsBangType }->	: atype				{ HsUnBangedTy $1 }->	| '!' atype			{ HsBangedTy   $2 }--> sbtype :: { HsBangType }->	: btype				{ HsUnBangedTy $1 }->	| '!' atype			{ HsBangedTy   $2 }--> fielddecls :: { [([HsName],HsBangType)] }->	: fielddecls ',' fielddecl	{ $3 : $1 }->	| fielddecl			{ [$1] }--> fielddecl :: { ([HsName],HsBangType) }->	: vars '::' stype		{ (reverse $1, $3) }--> stype :: { HsBangType }->	: type				{ HsUnBangedTy $1 }	->	| '!' atype			{ HsBangedTy   $2 }--> deriving :: { [HsQName] }->	: {- empty -}			{ [] }->	| 'deriving' qtycls		{ [$2] }->	| 'deriving' '('          ')'	{ [] }->	| 'deriving' '(' dclasses ')'	{ reverse $3 }--> dclasses :: { [HsQName] }->	: dclasses ',' qtycls		{ $3 : $1 }->       | qtycls			{ [$1] }--------------------------------------------------------------------------------Class declarations--> optcbody :: { [HsDecl] }->	: 'where' decllist		{% checkClassBody $2 }->	| {- empty -}			{ [] }--------------------------------------------------------------------------------Instance declarations--> optvaldefs :: { [HsDecl] }->	: 'where' '{'  valdefs '}'	{% checkClassBody $3 }->	| 'where' open valdefs close	{% checkClassBody $3 }->	| {- empty -}			{ [] }--> valdefs :: { [HsDecl] }->	: optsemis valdefs1 optsemis	{% checkRevDecls $2 }->	| optsemis			{ [] }--> valdefs1 :: { [HsDecl] }->	: valdefs1 semis valdef		{ $3 : $1 }->	| valdef			{ [$1] }--------------------------------------------------------------------------------Value definitions--> valdef :: { HsDecl }->	: srcloc exp0b rhs optwhere	{% checkValDef $1 $2 $3 $4 }--> optwhere :: { [HsDecl] }->	: 'where' decllist		{ $2 }->	| {- empty -}			{ [] }--> rhs	:: { HsRhs }->	: '=' exp			{% do { e <- checkExpr $2;->						return (HsUnGuardedRhs e) } }->	| gdrhs				{ HsGuardedRhss  (reverse $1) }--> gdrhs :: { [HsGuardedRhs] }->	: gdrhs gdrh			{ $2 : $1 }->	| gdrh				{ [$1] }--> gdrh :: { HsGuardedRhs }->	: srcloc '|' exp0 '=' exp	{% do { g <- checkExpr $3;->						e <- checkExpr $5;->						return (HsGuardedRhs $1 g e) } }--------------------------------------------------------------------------------Expressions--Note: The Report specifies a meta-rule for lambda, let and if expressions-(the exp's that end with a subordinate exp): they extend as far to-the right as possible.  That means they cannot be followed by a type-signature or infix application.  To implement this without shift/reduce-conflicts, we split exp10 into these expressions (exp10a) and the others-(exp10b).  That also means that only an exp0 ending in an exp10b (an exp0b)-can followed by a type signature or infix application.  So we duplicate-the exp0 productions to distinguish these from the others (exp0a).--> exp   :: { HsExp }->	: exp0b '::' srcloc ctype  	{ HsExpTypeSig $3 $1 $4 }->	| exp0				{ $1 }--> exp0 :: { HsExp }->	: exp0a				{ $1 }->	| exp0b				{ $1 }--> exp0a :: { HsExp }->	: exp0b qop exp10a		{ HsInfixApp $1 $2 $3 }->	| exp10a			{ $1 }--> exp0b :: { HsExp }->	: exp0b qop exp10b		{ HsInfixApp $1 $2 $3 }->	| exp10b			{ $1 }--> exp10a :: { HsExp }->	: '\\' srcloc apats '->' exp	{ HsLambda $2 (reverse $3) $5 }->  	| 'let' decllist 'in' exp	{ HsLet $2 $4 }->	| 'if' exp 'then' exp 'else' exp { HsIf $2 $4 $6 }->	| procExp { $1 }--> procExp :: { HsExp }-> : 'proc' apat '->' cmd		{ ArrSyn.translate $2 $4 }--> exp10b :: { HsExp }->	: 'case' exp 'of' altslist	{ HsCase $2 $4 }->	| '-' fexp			{ HsNegApp $2 }->  	| 'do' stmtlist			{ HsDo $2 }->	| fexp				{ $1 }--> fexp :: { HsExp }->	: fexp aexp			{ HsApp $1 $2 }->  	| aexp				{ $1 }--> apats :: { [HsPat] }->	: apats apat			{ $2 : $1 }->  	| apat				{ [$1] }--> apat :: { HsPat }->	: aexp				{% checkPattern $1 }--UGLY: Because patterns and expressions are mixed, aexp has to be split into-two rules: One right-recursive and one left-recursive. Otherwise we get two-reduce/reduce-errors (for as-patterns and irrefutable patters).--Even though the variable in an as-pattern cannot be qualified, we use-qvar here to avoid a shift/reduce conflict, and then check it ourselves-(as for vars above).--> aexp	:: { HsExp }->	: qvar '@' aexp			{% do { n <- checkUnQual $1;->						return (HsAsPat n $3) } }->	| '~' aexp			{ HsIrrPat $2 }->  	| aexp1				{ $1 }--Note: The first two alternatives of aexp1 are not necessarily record-updates: they could be labeled constructions.--> aexp1	:: { HsExp }->  	: aexp1 '{' '}' 		{% mkRecConstrOrUpdate $1 [] }->  	| aexp1 '{' fbinds '}' 		{% mkRecConstrOrUpdate $1 (reverse $3) }->  	| aexp2				{ $1 }--According to the Report, the left section (e op) is legal iff (e op x)-parses equivalently to ((e) op x).  Thus e must be an exp0b.--> aexp2	:: { HsExp }->	: qvar				{ HsVar $1 }->	| gcon				{ $1 }->  	| literal			{ HsLit $1 }->	| '(' exp ')'			{ HsParen $2 }->	| '(' texps ')'			{ HsTuple (reverse $2) }->	| '[' list ']'                  { $2 }->	| '(' exp0b qop ')'		{ HsLeftSection $2 $3  }->	| '(' qopm exp0 ')'		{ HsRightSection $2 $3 }->	| '_'				{ HsWildCard }--> commas :: { Int }->	: commas ','			{ $1 + 1 }->	| ','				{ 1 }--> texps :: { [HsExp] }->	: texps ',' exp			{ $3 : $1 }->	| exp ',' exp			{ [$3,$1] }--------------------------------------------------------------------------------List expressions--The rules below are little bit contorted to keep lexps left-recursive while-avoiding another shift/reduce-conflict.--> list :: { HsExp }->	: exp				{ HsList [$1] }->	| lexps 			{ HsList (reverse $1) }->	| exp '..'			{ HsEnumFrom $1 }->	| exp ',' exp '..' 		{ HsEnumFromThen $1 $3 }->	| exp '..' exp	 		{ HsEnumFromTo $1 $3 }->	| exp ',' exp '..' exp		{ HsEnumFromThenTo $1 $3 $5 }->	| exp '|' quals			{ HsListComp $1 (reverse $3) }--> lexps :: { [HsExp] }->	: lexps ',' exp 		{ $3 : $1 }->	| exp ',' exp			{ [$3,$1] }--------------------------------------------------------------------------------List comprehensions--> quals :: { [HsStmt] }->	: quals ',' qual		{ $3 : $1 }->	| qual				{ [$1] }--> qual  :: { HsStmt }->	: pat srcloc '<-' exp		{ HsGenerator $2 $1 $4 }->	| exp				{ HsQualifier $1 }->  	| 'let' decllist		{ HsLetStmt $2 }--------------------------------------------------------------------------------Case alternatives--> altslist :: { [HsAlt] }->	: '{'  alts '}'			{ $2 }->	| open alts close		{ $2 }--> alts :: { [HsAlt] }->	: optsemis alts1 optsemis	{ reverse $2 }--> alts1 :: { [HsAlt] }->	: alts1 semis alt		{ $3 : $1 }->	| alt				{ [$1] }--> alt :: { HsAlt }->	: srcloc pat ralt optwhere	{ HsAlt $1 $2 $3 $4 }--> ralt :: { HsGuardedAlts }->	: '->' exp			{ HsUnGuardedAlt $2 }->	| gdpats			{ HsGuardedAlts (reverse $1) }--> gdpats :: { [HsGuardedAlt] }->	: gdpats gdpat			{ $2 : $1 }->	| gdpat				{ [$1] }--> gdpat	:: { HsGuardedAlt }->	: srcloc '|' exp0 '->' exp	{ HsGuardedAlt $1 $3 $5 }--> pat :: { HsPat }->	: exp0b				{% checkPattern $1 }--------------------------------------------------------------------------------Statement sequences--As per the Report, but with stmt expanded to simplify building the list-without introducing conflicts.  This also ensures that the last stmt is-an expression.--> stmtlist :: { [HsStmt] }->	: '{'  stmts '}'		{ $2 }->	| open stmts close		{ $2 }--> stmts :: { [HsStmt] }->	: 'let' decllist ';' stmts	{ HsLetStmt $2 : $4 }->	| pat srcloc '<-' exp ';' stmts	{ HsGenerator $2 $1 $4 : $6 }->	| exp ';' stmts			{ HsQualifier $1 : $3 }->	| ';' stmts			{ $2 }->	| exp ';'			{ [HsQualifier $1] }->	| exp				{ [HsQualifier $1] }--------------------------------------------------------------------------------Record Field Update/Construction--> fbinds :: { [HsFieldUpdate] }->	: fbinds ',' fbind		{ $3 : $1 }->	| fbind				{ [$1] }--> fbind	:: { HsFieldUpdate }->	: qvar '=' exp			{ HsFieldUpdate $1 $3 }--------------------------------------------------------------------------------Commands (for arrow expressions)-Largely analogous to the treatment of exp (qv), including the distinctions-exp0a/exp0b and exp10a/exp10b.--> cmd :: { ArrSyn.Cmd }->	: exp0b '-<' exp		{ ArrSyn.Input $1 $3 }->	| exp0b '-<<' exp		{ ArrSyn.Input $1 $3 }->	| exp0b '>-' exp		{ ArrSyn.Input $3 $1 }->	| exp0b '>>-' exp		{ ArrSyn.Input $3 $1 }->	| cmd0				{ $1 }--> cmd0 :: { ArrSyn.Cmd }->	: cmd0a				{ $1 }->	| cmd0b				{ $1 }--> cmd0a :: { ArrSyn.Cmd }->	: cmd0b qop cmd10a		{ ArrSyn.InfixOp $1 $2 $3 }->	| cmd10a			{ $1 }--> cmd0b :: { ArrSyn.Cmd }->	: cmd0b qop cmd10b		{ ArrSyn.InfixOp $1 $2 $3 }->	| cmd10b			{ $1 }--> cmd10a :: { ArrSyn.Cmd }->	: '\\' srcloc apats '->' cmd	{ ArrSyn.Kappa $2 (reverse $3) $5 }->	| 'let' decllist 'in' cmd	{ ArrSyn.Let $2 $4 }->	| 'let' cmddecl 'in' cmd	{ ArrSyn.LetCmd $2 $4 }->	| 'if' exp 'then' cmd 'else' cmd { ArrSyn.If $2 $4 $6 }--> cmd10b :: { ArrSyn.Cmd }->	: 'case' exp 'of' altslistA	{ ArrSyn.Case $2 $4 }->	| 'do' stmtlistA		{ ArrSyn.Do (fst $2) (snd $2) }->	| fcmd				{ $1 }--> fcmd :: { ArrSyn.Cmd }->	: fcmd aexp			{ ArrSyn.App $1 $2 }->	| acmd				{ $1 }--> acmd :: { ArrSyn.Cmd }->	: '(' cmd ')'			{ ArrSyn.Paren $2 }->	| '(|' aexp acmds '|)'		{ ArrSyn.Op $2 (reverse $3) }->	| 'cmd' varid			{ ArrSyn.CmdVar $2 }--> acmds :: { [ArrSyn.Cmd] }->	: acmds acmd			{ $2 : $1 }->	| acmd				{ [$1] }--Case commands--> altslistA :: { [ArrSyn.Alt] }->	: '{'  altsA '}'		{ $2 }->	| open altsA close		{ $2 }--> altsA :: { [ArrSyn.Alt] }->	: optsemis alts1A optsemis	{ reverse $2 }--> alts1A :: { [ArrSyn.Alt] }->	: alts1A semis altA		{ $3 : $1 }->	| altA				{ [$1] }--> altA :: { ArrSyn.Alt }->	: srcloc pat raltA optwhere	{ ArrSyn.Alt $1 $2 $3 $4 }--> raltA :: { ArrSyn.GuardedAlts }->	: '->' cmd			{ ArrSyn.UnGuardedAlt $2 }->	| gdpatsA			{ ArrSyn.GuardedAlts (reverse $1) }--> gdpatsA :: { [ArrSyn.GuardedAlt] }->	: gdpatsA gdpatA		{ $2 : $1 }->	| gdpatA			{ [$1] }--> gdpatA :: { ArrSyn.GuardedAlt }->	: srcloc '|' exp0 '->' cmd	{ ArrSyn.GuardedAlt $1 $3 $5 }--The arrow version of do statements--> stmtlistA :: { ArrSyn.Stmts }->	: '{'  stmtsA '}'		{ $2 }->	| open stmtsA close		{ $2 }--Note that stmts/stmtsA must be right-recursive; otherwise it is not-possible, in situations like--	'proc' pat '->' 'do' '(' 'let' decls . ';'--to choose between the productions--	qual -> 'let' decls-	qualA -> 'let' decls--Now that decision is delayed until the trailing exp/cmd is seen.--> stmtsA :: { ArrSyn.Stmts }->	: squalA ';' stmtsA		{ ($1 : fst $3, snd $3) }->	| cmd ';' stmtsA		{ (ArrSyn.Generator undefined HsPWildCard $1 : fst $3, snd $3) }->	| 'let' decllist ';' stmtsA	{ (ArrSyn.LetStmt $2 : fst $4, snd $4) }->	| ';' stmtsA			{ $2 }->	| cmd ';'			{ ([], $1) }->	| cmd				{ ([], $1) }--> squalA :: { ArrSyn.Stmt }->	: pat srcloc '<-' cmd		{ ArrSyn.Generator $2 $1 $4 }->	| cmd '->' srcloc pat		{ ArrSyn.Generator $3 $4 $1 }->	| 'rec' defnsA			{ ArrSyn.RecStmt (reverse $2) }->	| 'let' cmddecl			{ ArrSyn.LetCmdStmt $2 }--> cmddecl :: { ArrSyn.VarDecl ArrSyn.Cmd }->	: srcloc 'cmd' varid '=' cmd	{ ArrSyn.VarDecl $1 $3 $5 }--> defnsA :: { [ArrSyn.Stmt] }->	: '{'  stmts1A '}'		{ $2 }->	| open stmts1A close		{ $2 }--> stmts1A :: { [ArrSyn.Stmt] }->	: stmts1A ';' qualA		{ $3 : $1 }->	| qualA				{ [$1] }--> qualA :: { ArrSyn.Stmt }->	: squalA			{ $1 }->	| 'let' decllist		{ ArrSyn.LetStmt $2 }--------------------------------------------------------------------------------Variables, Constructors and Operators.--> gcon :: { HsExp }->  	: '(' ')'		{ unit_con }->	| '[' ']'		{ HsList [] }->	| '(' commas ')'	{ tuple_con $2 }->  	| qcon			{ HsCon $1 }--> var 	:: { HsName }->	: varid			{ $1 }->	| '(' varsym ')'	{ $2 }--> qvar 	:: { HsQName }->	: qvarid		{ $1 }->	| '(' qvarsym ')'	{ $2 }--> con	:: { HsName }->	: conid			{ $1 }->	| '(' consym ')'        { $2 }--> qcon	:: { HsQName }->	: qconid		{ $1 }->	| '(' gconsym ')'	{ $2 }--> varop	:: { HsName }->	: varsym		{ $1 }->	| '`' varid '`'		{ $2 }--> qvarop :: { HsQName }->	: qvarsym		{ $1 }->	| '`' qvarid '`'	{ $2 }--> qvaropm :: { HsQName }->	: qvarsymm		{ $1 }->	| '`' qvarid '`'	{ $2 }--> conop :: { HsName }->	: consym		{ $1 }	->	| '`' conid '`'		{ $2 }--> qconop :: { HsQName }->	: gconsym		{ $1 }->	| '`' qconid '`'	{ $2 }--> op	:: { HsOp }->	: varop			{ HsVarOp $1 }->	| conop 		{ HsConOp $1 }--> qop	:: { HsQOp }->	: qvarop		{ HsQVarOp $1 }->	| qconop		{ HsQConOp $1 }--> qopm	:: { HsQOp }->	: qvaropm		{ HsQVarOp $1 }->	| qconop		{ HsQConOp $1 }--> gconsym :: { HsQName }->	: ':'			{ list_cons_name }->	| qconsym		{ $1 }--------------------------------------------------------------------------------Identifiers and Symbols--> qvarid :: { HsQName }->	: varid			{ UnQual $1 }->	| QVARID		{ Qual (Module (fst $1)) (HsIdent (snd $1)) }--> varid :: { HsName }->	: VARID			{ HsIdent $1 }->	| 'as'			{ HsIdent "as" }->	| 'export'		{ HsIdent "export" }->	| 'hiding'		{ HsIdent "hiding" }->	| 'qualified'		{ HsIdent "qualified" }->	| 'safe'		{ HsIdent "safe" }->	| 'unsafe'		{ HsIdent "unsafe" }--> qconid :: { HsQName }->	: conid			{ UnQual $1 }->	| QCONID		{ Qual (Module (fst $1)) (HsIdent (snd $1)) }--> conid :: { HsName }->	: CONID			{ HsIdent $1 }--> qconsym :: { HsQName }->	: consym		{ UnQual $1 }->	| QCONSYM		{ Qual (Module (fst $1)) (HsSymbol (snd $1)) }--> consym :: { HsName }->	: CONSYM		{ HsSymbol $1 }--> qvarsym :: { HsQName }->	: varsym		{ UnQual $1 }->	| qvarsym1		{ $1 }--> qvarsymm :: { HsQName }->	: varsymm		{ UnQual $1 }->	| qvarsym1		{ $1 }--> varsym :: { HsName }->	: VARSYM		{ HsSymbol $1 }->	| '-'			{ HsSymbol "-" }->	| '!'			{ HsSymbol "!" }--> varsymm :: { HsName } -- varsym not including '-'->	: VARSYM		{ HsSymbol $1 }->	| '!'			{ HsSymbol "!" }--> qvarsym1 :: { HsQName }->	: QVARSYM		{ Qual (Module (fst $1)) (HsSymbol (snd $1)) }--> literal :: { HsLiteral }->	: INT			{ HsInt $1 }->	| CHAR 			{ HsChar $1 }->	| RATIONAL		{ HsFrac $1 }->	| STRING		{ HsString $1 }--> srcloc :: { SrcLoc }	:	{% getSrcLoc }- -------------------------------------------------------------------------------Layout--> open  :: { () }	:	{% pushCurrentContext }--> close :: { () }->	: vccurly		{ () } -- context popped in lexer.->	| error			{% popContext }--------------------------------------------------------------------------------Miscellaneous (mostly renamings)--> modid :: { Module }->	: CONID			{ Module $1 }->	| QCONID		{ Module (fst $1 ++ '.':snd $1) }--> tyconorcls :: { HsName }->	: conid			{ $1 }--> tycon :: { HsName }->	: conid			{ $1 }--> qtyconorcls :: { HsQName }->	: qconid		{ $1 }--> qtycls :: { HsQName }->	: qconid		{ $1 }--> tyvar :: { HsName }->	: varid			{ $1 }---------------------------------------------------------------------------------> {-> happyError :: P a-> happyError = fail "Parse error"--> -- | Parse of a string, which should contain a complete Haskell 98 module.-> parseModule :: String -> ParseResult HsModule-> parseModule = runParser parse--> -- | Parse of a string, which should contain a complete Haskell 98 module.-> parseModuleWithMode :: ParseMode -> String -> ParseResult HsModule-> parseModuleWithMode mode = runParserWithMode mode parse->-> parseProc :: String -> ParseResult HsExp-> parseProc = runParser parseProcExp-> }
− src/State.hs
@@ -1,6 +0,0 @@--- A Haskell-98-compatible subset of the Control.Monad.State module.--module State(State, runState, get, put) where--import Control.Monad.Trans.State-
+ src/Utils.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE DeriveDataTypeable  #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE OverloadedLists     #-}+{-# LANGUAGE RankNTypes          #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections       #-}+{-# LANGUAGE TypeFamilies        #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing -Wno-orphans #-}+module Utils+  ( module Utils+  , HSE.Located(..)+  , HSE.rebracket1+  )where++import           Control.Monad+import           Control.Monad.Trans.State+import           Data.Data+import           Data.Default+import           Data.Functor.Identity+import           Data.Generics.Uniplate.Data+import           Data.List+import           Data.Map                      (Map)+import           Data.Set                      (Set)+import qualified Data.Set                      as Set+import           Debug.Hoed.Pure               hiding (Module)+import           Language.Haskell.Exts+import qualified Language.Haskell.Exts.Util    as HSE+#ifdef DEBUG+import           Language.Haskell.Exts.Observe ()+#endif++-- | The type of src code locations used by arrowp-qq+newtype S = S {getSrcSpanInfo :: SrcSpanInfo}+  deriving (Data, Typeable)+instance Eq S where _ == _ = True+instance Ord S where compare _ _ = EQ+instance Show S where show _ = "<loc>"++instance Default S where+  def = S noSrcSpan++instance Observable S where+  observer = observeOpaque "<loc>"+  constrain = constrainBase++freeVars+  :: (Observable a, HSE.FreeVars a, S ~ HSE.LocType a)+  => a -> Set (Name S)+freeVars = observe "freeVars" HSE.freeVars++freeVarss+  :: (Observable a, HSE.AllVars a, S ~ HSE.LocType a)+  => a -> Set (Name S)+freeVarss = observe "freeVarss" (HSE.free . HSE.allVars)++definedVars+  :: (Observable a, HSE.AllVars a, S ~ HSE.LocType a)+  => a -> Set (Name S)+definedVars = observe "definedVars" (HSE.bound . HSE.allVars)++-- | Are a tuple pattern and an expression tuple equal ?+same :: Pat S -> Exp S -> Bool+same = observe "same" same'++same' :: Pat S -> Exp S -> Bool+same' (PApp _ n1 []) (Con _ n2) = n1 == n2+same' (PVar l n1) (Var _ n2) = UnQual l n1 == n2+same' (PTuple _ Boxed []) y = same (PApp (ann y) (unit_con_name (ann y)) []) y+same' (PTuple _ Boxed [pv]) y = same pv y+same' y (Tuple _ Boxed []) = same y (unit_con(ann y))+same' y (Tuple _ Boxed [pv]) = same y pv+same' (PTuple _ boxed ps) (Tuple _ boxed' es) =+  length ps == length es && boxed == boxed' && and (zipWith same ps es)+same' (PAsPat _ n _) (Var _ (UnQual _ n')) = n == n'+same' (PAsPat _ _ p) e = same p e+same' (PParen _ p) e = same p e+same' p (Paren _ e) = same p e+same' _ _ = False++times :: Int -> (a -> a) -> a -> a+times n f x = iterate f x !! n++-- | Hide variables from a pattern+hidePat :: Set (Name S) -> Pat S -> Pat S+hidePat vs = transform (go vs) where+  go vs p@(PVar l n)+    | n `Set.member` vs = PWildCard l+    | otherwise = p+  go vs (PAsPat _ n p)+    | n `Set.member` vs = go vs p+  go _ x = x++pair :: Exp S -> Exp S -> Exp S+pair e1 e2 = Tuple (ann e1) Boxed [e1, e2]++pairP :: Pat S -> Pat S -> Pat S+pairP p1 p2 = PTuple (ann p1) Boxed [hidePat (definedVars p2) p1, p2]++left, right :: Exp S -> Exp S+left  x = App (ann x) left_exp  (Paren def x)+right x = App (ann x) right_exp (Paren def x)++returnCmd :: Exp S -> Exp S+returnCmd x = LeftArrApp (ann x) returnA_exp x++compose_op, choice_op :: QOp S+returnA_exp, arr_exp, first_exp :: Exp S+left_exp, right_exp, app_exp, loop_exp :: Exp S+unqualId :: String -> Exp S+unqualId   id = Var def $ UnQual def (Ident def id)+unqualOp :: String -> QOp S+unqualOp id = QVarOp def $ UnQual def (Symbol def id)+unqualCon :: String -> Exp S+unqualCon  id = Con def $ UnQual def (Symbol def id)+arr_exp       = unqualId "arr"+compose_op    = unqualOp ">>>"+first_exp     = unqualId "first"+returnA_exp   = unqualId "returnA"+choice_op     = unqualOp "|||"+left_exp      = unqualCon "Left"+right_exp     = unqualCon "Right"+app_exp       = unqualId "app"+loop_exp      = unqualId "loop"+++-- | Irrefutable version of a pattern++irrPat :: Pat S -> Pat S+irrPat p@PVar{}       = p+irrPat (PParen l p)   = PParen l (irrPat p)+irrPat (PAsPat l n p) = PAsPat l n (irrPat p)+irrPat p@PWildCard{}  = p+irrPat p@PIrrPat{}    = p+irrPat p              = PIrrPat (ann p) p++-- | Observing functions for algorithmic debugging++observeSt+  :: (Observable a, Observable b, Observable c, Observable s)+  => String -> (a -> b -> State s c) -> a -> b -> State s c+observeSt name f a b = StateT $ \s -> Identity $ observe name f' a b s+  where+    f' a b = runState (f a b)++instance (Eq a, Show a) => Observable (Set a) where+  constrain = constrainBase+  observer = observeBase++instance (Eq a, Eq k, Show a, Show k) => Observable (Map k a) where+  constrain = constrainBase+  observer = observeBase++-- Override some AST instances for comprehension+instance {-# OVERLAPS #-} Observable (Exp S) where+  observer = observePretty+instance {-# OVERLAPS #-} Observable (Name S) where+  observer = observePretty+instance {-# OVERLAPS #-} Observable (QName S) where+  observer = observePretty+instance {-# OVERLAPS #-} Observable [Stmt S] where+  observer lit cxt =+    seq lit $ send (bracket $ intercalate ";" $ fmap prettyPrint lit) (return lit) cxt+instance {-# OVERLAPS #-} Observable (Stmt S) where+  observer = observePretty+instance {-# OVERLAPS #-} Observable (Pat S) where+  observer = observePretty+instance {-# OVERLAPS #-} Observable (QOp S) where+  observer = observePretty+instance {-# OVERLAPS #-} Observable (Op S) where+  observer = observePretty+instance {-# OVERLAPS #-} Observable (Rhs S) where+  observer = observePretty+instance {-# OVERLAPS #-} Observable (Alt S) where+  observer = observePretty+instance {-# OVERLAPS #-} Observable (Set (Name S)) where+  constrain = constrainBase+  observer x cxt =+    seq x $ send (between "[" "]"$ intercalate "," $ prettyPrint <$> map void (Set.toList x)) (return x) cxt++observePretty lit cxt =+  seq lit $ send (between "<" ">" $ prettyPrint lit) (return lit) cxt++bracket :: [Char] -> [Char]+between open  close s = open ++ s ++ close+bracket = between "[" "]"
− src/Utils.lhs
@@ -1,204 +0,0 @@-Miscellaneous utilities on ordinary Haskell syntax used by the arrow-translator.--> module Utils(->	FreeVars(freeVars), DefinedVars(definedVars),->	failureFree, irrPat, paren, parenInfixArg,->	tuple, tupleP,->	times-> ) where--> import Data.Set (Set)-> import qualified Data.Set as Set-> import Language.Haskell.Syntax--The set of free variables in some construct.--> class FreeVars a where->	freeVars :: a -> Set HsName--> instance FreeVars a => FreeVars [a] where->	freeVars = Set.unions . map freeVars--> instance FreeVars HsPat where->	freeVars (HsPVar n) = Set.singleton n->	freeVars (HsPLit _) = Set.empty->	freeVars (HsPNeg p) = freeVars p->	freeVars (HsPInfixApp p1 _ p2) = freeVars p1 `Set.union` freeVars p2->	freeVars (HsPApp _ ps) = freeVars ps->	freeVars (HsPTuple ps) = freeVars ps->	freeVars (HsPList ps) = freeVars ps->	freeVars (HsPParen p) = freeVars p->	freeVars (HsPRec _ pfs) = freeVars pfs->	freeVars (HsPAsPat n p) = Set.insert n (freeVars p)->	freeVars (HsPWildCard) = Set.empty->	freeVars (HsPIrrPat p) = freeVars p--> instance FreeVars HsPatField where->	freeVars (HsPFieldPat _ p) = freeVars p--> instance FreeVars HsFieldUpdate where->	freeVars (HsFieldUpdate _ e) = freeVars e--> instance FreeVars HsExp where->	freeVars (HsVar n) = freeVars n->	freeVars (HsCon _) = Set.empty->	freeVars (HsLit _) = Set.empty->	freeVars (HsInfixApp e1 op e2) =->		freeVars e1 `Set.union` freeVars op `Set.union` freeVars e2->	freeVars (HsApp f e) = freeVars f `Set.union` freeVars e->	freeVars (HsNegApp e) = freeVars e->	freeVars (HsLambda _ ps e) = freeVars e `Set.difference` freeVars ps->	freeVars (HsLet decls e) =->		(freeVars decls `Set.union` freeVars e) `Set.difference`->			definedVars decls->	freeVars (HsIf e1 e2 e3) =->		freeVars e1 `Set.union` freeVars e2 `Set.union` freeVars e3->	freeVars (HsCase e as) = freeVars e `Set.union` freeVars as->	freeVars (HsDo ss) = freeVarsStmts ss->	freeVars (HsTuple es) = freeVars es->	freeVars (HsList es) = freeVars es->	freeVars (HsParen e) = freeVars e->	freeVars (HsLeftSection e op) = freeVars e `Set.union` freeVars op->	freeVars (HsRightSection op e) = freeVars op `Set.union` freeVars e->	freeVars (HsRecConstr _ us) = freeVars us->	freeVars (HsRecUpdate e us) = freeVars e `Set.union` freeVars us->	freeVars (HsEnumFrom e) = freeVars e->	freeVars (HsEnumFromTo e1 e2) = freeVars e1 `Set.union` freeVars e2->	freeVars (HsEnumFromThen e1 e2) = freeVars e1 `Set.union` freeVars e2->	freeVars (HsEnumFromThenTo e1 e2 e3) =->		freeVars e1 `Set.union` freeVars e2 `Set.union` freeVars e3->	freeVars (HsListComp e ss) =->		freeVars e `Set.union` freeVarsStmts ss->	freeVars (HsExpTypeSig _ e _) = freeVars e->	freeVars (HsAsPat _ _) = error "freeVars (x @ p)"->	freeVars (HsWildCard) = error "freeVars _"->	freeVars (HsIrrPat _) = error "freeVars ~p"--> instance FreeVars HsQOp where->	freeVars (HsQVarOp n) = freeVars n->	freeVars (HsQConOp _) = Set.empty--> instance FreeVars HsQName where->	freeVars (UnQual v) = Set.singleton v->	freeVars _ = Set.empty--> instance FreeVars HsAlt where->	freeVars (HsAlt _ p gas decls) =->		(freeVars gas `Set.union` freeVars decls) `Set.difference`->		(freeVars p `Set.union` definedVars decls)--> instance FreeVars HsGuardedAlts where->	freeVars (HsUnGuardedAlt e) = freeVars e->	freeVars (HsGuardedAlts alts) = freeVars alts--> instance FreeVars HsGuardedAlt where->	freeVars (HsGuardedAlt _ e1 e2) = freeVars e1 `Set.union` freeVars e2--> instance FreeVars HsDecl where->	freeVars (HsFunBind ms) = freeVars ms->	freeVars (HsPatBind _ p rhs decls) =->		(freeVars rhs `Set.union` freeVars decls) `Set.difference`->		(freeVars p `Set.union` definedVars decls)->	freeVars _ = Set.empty--> instance FreeVars HsMatch where->	freeVars (HsMatch _ n ps rhs decls) =->		(freeVars rhs `Set.union` freeVars decls) `Set.difference`->		(Set.insert n (freeVars ps) `Set.union` definedVars decls)--> instance FreeVars HsRhs where->	freeVars (HsUnGuardedRhs e) = freeVars e->	freeVars (HsGuardedRhss grs) = freeVars grs--> instance FreeVars HsGuardedRhs where->	freeVars (HsGuardedRhs _ e1 e2) = freeVars e1 `Set.union` freeVars e2--> freeVarsStmts :: [HsStmt] -> Set HsName-> freeVarsStmts = foldr addStmt Set.empty->	where	addStmt (HsGenerator _ p e) s =->			freeVars e `Set.union` (s `Set.difference` freeVars p)->		addStmt (HsQualifier e) _s = freeVars e->		addStmt (HsLetStmt decls) s =->			(freeVars decls `Set.union` s) `Set.difference` definedVars decls--The set of variables defined by a construct.--> class DefinedVars a where->	definedVars :: a -> Set HsName--> instance DefinedVars a => DefinedVars [a] where->	definedVars = Set.unions . map definedVars--> instance DefinedVars HsDecl where->	definedVars (HsFunBind (HsMatch _ n _ _ _:_)) = Set.singleton n->	definedVars (HsPatBind _ p _ _) = freeVars p->	definedVars _ = Set.empty--Is the pattern failure-free?-(This is incomplete at the moment, because patterns made with unique-constructors should be failure-free, but we have no way of detecting them.)--> failureFree :: HsPat -> Bool-> failureFree (HsPVar _) = True-> failureFree (HsPApp n ps) = n == unit_con_name && null ps-> failureFree (HsPTuple ps) = all failureFree ps-> failureFree (HsPParen p) = failureFree p-> failureFree (HsPAsPat _ p) = failureFree p-> failureFree (HsPWildCard) = True-> failureFree (HsPIrrPat _) = True-> failureFree _ = False--Irrefutable version of a pattern--> irrPat :: HsPat -> HsPat-> irrPat p@(HsPVar _) = p-> irrPat (HsPParen p) = HsPParen (irrPat p)-> irrPat (HsPAsPat n p) = HsPAsPat n (irrPat p)-> irrPat p@(HsPWildCard) = p-> irrPat p@(HsPIrrPat _) = p-> irrPat p = HsPIrrPat p--Make an expression into an aexp, by adding parentheses if required.--> paren :: HsExp -> HsExp-> paren e = if isAexp e then e else HsParen e->	where	isAexp (HsVar _) = True->		isAexp (HsCon _) = True->		isAexp (HsLit _) = True->		isAexp (HsParen _) = True->		isAexp (HsTuple _) = True->		isAexp (HsList _) = True->		isAexp (HsEnumFrom _) = True->		isAexp (HsEnumFromTo _ _) = True->		isAexp (HsEnumFromThen _ _) = True->		isAexp (HsEnumFromThenTo _ _ _) = True->		isAexp (HsListComp _ _) = True->		isAexp (HsLeftSection _ _) = True->		isAexp (HsRightSection _ _) = True->		isAexp (HsRecConstr _ _) = True->		isAexp (HsRecUpdate _ _) = True->		isAexp _ = False--Make an expression into an fexp, by adding parentheses if required.--> parenInfixArg :: HsExp -> HsExp-> parenInfixArg e@(HsApp _ _) = e-> parenInfixArg e = paren e--Tuples--> tuple :: [HsExp] -> HsExp-> tuple [] = unit_con-> tuple [e] = e-> tuple es = HsTuple es--> tupleP :: [HsPat] -> HsPat-> tupleP [] = HsPApp unit_con_name []-> tupleP [e] = e-> tupleP es = HsPTuple es--Compose a function n times.--> times :: Int -> (a -> a) -> a -> a-> times n f a = foldr ($) a (replicate n f)