FerryCore (empty) → 0.4.5
raw patch · 43 files changed
+3686/−0 lines, 43 filesdep +HaXmldep +TableAlgebradep +basesetup-changed
Dependencies added: HaXml, TableAlgebra, base, containers, haskell98, mtl, parsec, pretty, template-haskell
Files
- FerryCore.cabal +72/−0
- LICENSE +27/−0
- Setup.hs +4/−0
- src/Database/Ferry/Common/Data/Base.hs +27/−0
- src/Database/Ferry/Common/Render/Dot.hs +153/−0
- src/Database/Ferry/Common/Render/Pretty.hs +26/−0
- src/Database/Ferry/Compiler.hs +16/−0
- src/Database/Ferry/Compiler/Error/Error.hs +35/−0
- src/Database/Ferry/Compiler/ExecuteStep.hs +51/−0
- src/Database/Ferry/Compiler/Pipeline.hs +27/−0
- src/Database/Ferry/Compiler/Stages.hs +10/−0
- src/Database/Ferry/Compiler/Stages/AlgebraToXMLStage.hs +22/−0
- src/Database/Ferry/Compiler/Stages/BoxingStage.hs +32/−0
- src/Database/Ferry/Compiler/Stages/RewriteStage.hs +29/−0
- src/Database/Ferry/Compiler/Stages/ToAlgebraStage.hs +24/−0
- src/Database/Ferry/Compiler/Stages/TypeInferStage.hs +38/−0
- src/Database/Ferry/Compiler/Transform.hs +24/−0
- src/Database/Ferry/Compiler/Types.hs +164/−0
- src/Database/Ferry/Core/Data/Core.hs +59/−0
- src/Database/Ferry/Core/Render/Dot.hs +97/−0
- src/Database/Ferry/Core/Render/Pretty.hs +15/−0
- src/Database/Ferry/Impossible.hs +11/−0
- src/Database/Ferry/Syntax.hs +16/−0
- src/Database/Ferry/SyntaxTyped.hs +16/−0
- src/Database/Ferry/TypeSystem/AlgorithmW.hs +220/−0
- src/Database/Ferry/TypeSystem/ContextReduction.hs +38/−0
- src/Database/Ferry/TypeSystem/Prelude.hs +109/−0
- src/Database/Ferry/TypeSystem/Types.hs +97/−0
- src/Database/Ferry/TypeSystem/Unification.hs +109/−0
- src/Database/Ferry/TypedCore/Boxing/Boxing.hs +243/−0
- src/Database/Ferry/TypedCore/Convert/CoreToAlgebra.hs +960/−0
- src/Database/Ferry/TypedCore/Convert/Specialize.hs +25/−0
- src/Database/Ferry/TypedCore/Convert/Traverse.hs +65/−0
- src/Database/Ferry/TypedCore/Data/Instances.hs +155/−0
- src/Database/Ferry/TypedCore/Data/Substitution.hs +19/−0
- src/Database/Ferry/TypedCore/Data/Type.hs +106/−0
- src/Database/Ferry/TypedCore/Data/TypeClasses.hs +46/−0
- src/Database/Ferry/TypedCore/Data/TypeFunction.hs +31/−0
- src/Database/Ferry/TypedCore/Data/TypedCore.hs +52/−0
- src/Database/Ferry/TypedCore/Render/Dot.hs +122/−0
- src/Database/Ferry/TypedCore/Render/Pretty.hs +44/−0
- src/Database/Ferry/TypedCore/Rewrite/Combinators.hs +75/−0
- src/Database/Ferry/TypedCore/Rewrite/OpRewrite.hs +175/−0
+ FerryCore.cabal view
@@ -0,0 +1,72 @@+cabal-version: >=1.8+Name: FerryCore+Version: 0.4.5+category: Database+Synopsis: Ferry Core Components+Description: The Ferry 2.0 Core+ This package contains the core components of the Ferry compiler [1]. It lacks a parser+ for the ferry language and the normalisation ferry front, and the conversion of ferry+ front language to the ferry core language.+ . + It exposes the compiler parts that transform (un)typed ferry core into table algebra [2].+ When provided an untyped ferrycore AST this ast must have the shape of a normalised+ ferry program. When a typed ast is used as input it is required to be typed correctly as well.+ The ferry compiler uses this package providing it untyped ferrycore. DSH [3] uses this+ package providing a typed AST.+ .+ 1. <http://www-db.informatik.uni-tuebingen.de/research/ferry>+ .+ 2. <http://dbworld.informatik.uni-tuebingen.de/projects/pathfinder/wiki/Logical_Algebra>+ .+ 3. <http://www-db.informatik.uni-tuebingen.de/files/publications/ferryhaskell.pdf>+License: BSD3+License-file: LICENSE+Author: Jeroen Weijers <jeroen.weijers@uni-tuebingen.de> Tom Schreiber <tom.schreiber@uni-tuebingen.de>+Maintainer: Jeroen Weijers <jeroen.weijers@uni-tuebingen.de>+Build-Type: Simple+library+ buildable: True+ build-depends: TableAlgebra >= 0.1.5, base >= 4.2 && < 5, HaXml >= 1.20.2, pretty >= 1.0.1.1, parsec >= 2.1.0.1, mtl >= 2.0.1.0, containers >= 0.3.0.0, haskell98 >= 1.0.1.1, template-haskell >= 2.4.0.0+ exposed-modules: Database.Ferry.Syntax+ Database.Ferry.Compiler+ Database.Ferry.SyntaxTyped+ hs-source-dirs: src+ GHC-Options: -Wall -fno-warn-orphans -fno-warn-type-defaults -fno-warn-unused-do-bind + other-modules:+ Database.Ferry.Common.Render.Dot + Database.Ferry.Common.Render.Pretty + Database.Ferry.Compiler.Error.Error + Database.Ferry.Compiler.ExecuteStep + Database.Ferry.Compiler.Stages+ Database.Ferry.Compiler.Transform+ Database.Ferry.Compiler.Pipeline+ Database.Ferry.Compiler.Stages.AlgebraToXMLStage + Database.Ferry.Compiler.Stages.BoxingStage + Database.Ferry.Compiler.Stages.RewriteStage + Database.Ferry.Compiler.Stages.ToAlgebraStage + Database.Ferry.Compiler.Stages.TypeInferStage + Database.Ferry.Compiler.Types + Database.Ferry.Core.Data.Core + Database.Ferry.Core.Render.Dot + Database.Ferry.Core.Render.Pretty + Database.Ferry.TypedCore.Boxing.Boxing + Database.Ferry.TypedCore.Convert.CoreToAlgebra + Database.Ferry.TypedCore.Convert.Specialize + Database.Ferry.TypedCore.Convert.Traverse + Database.Ferry.TypedCore.Data.Instances + Database.Ferry.TypedCore.Data.Substitution + Database.Ferry.TypedCore.Data.Type + Database.Ferry.TypedCore.Data.TypeClasses + Database.Ferry.TypedCore.Data.TypedCore + Database.Ferry.TypedCore.Data.TypeFunction + Database.Ferry.TypedCore.Render.Dot + Database.Ferry.TypedCore.Render.Pretty + Database.Ferry.TypedCore.Rewrite.Combinators + Database.Ferry.TypedCore.Rewrite.OpRewrite + Database.Ferry.TypeSystem.AlgorithmW + Database.Ferry.TypeSystem.ContextReduction + Database.Ferry.TypeSystem.Prelude + Database.Ferry.TypeSystem.Types + Database.Ferry.TypeSystem.Unification+ Database.Ferry.Common.Data.Base+ Database.Ferry.Impossible
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) Eberhard Karls Universität Tübingen 2010++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,4 @@+import Distribution.Simple++main = defaultMain+
+ src/Database/Ferry/Common/Data/Base.hs view
@@ -0,0 +1,27 @@+{- | +This module contains some datatypes and functions that are used at various stages in the compiler.+-}+module Database.Ferry.Common.Data.Base where++-- | Identifiers are represented as strings +type Identifier = String++-- | Constant values+data Const = CInt Integer+ | CFloat Double+ | CBool Bool+ | CString String+ | CUnit+ deriving (Show, Eq)++-- | Type class for extracting all variables that occur in a value of type a+class VarContainer a where+ vars :: a -> [Identifier]++-- | Print constants +toString :: Const -> String+toString (CInt i) = show i+toString (CFloat d) = show d+toString (CBool b) = show b+toString (CString s) = s+toString (CUnit) = "()"
+ src/Database/Ferry/Common/Render/Dot.hs view
@@ -0,0 +1,153 @@+{-# LANGUAGE TypeSynonymInstances #-}+{-| Infrastructure for generating Dot graphics files.+-}+module Database.Ferry.Common.Render.Dot where+ +import Database.Ferry.Compiler.Error.Error++import Control.Monad.Error+import Control.Monad.Writer+import Control.Monad.State++import qualified Data.List as L++-- | Class for transforming values into either an error or a string representing a dot file.+class Dotify a where+ dot :: a -> Either FerryError String++-- | Dot files are internally represented as a list of nodes and a list of edges+data DotFile = DotFile [Node] [Edge]++-- | A dot Id is just string+type Id = String++-- | A dot Node has an id (unique) and a list of properties decribing its shape+data Node = Node Id [NodeProp]++-- | An edge runs from one node to one or more others identified by unique ids+data Edge = Edge Id [Id]++-- | Node properties describing shape of a node+data NodeProp = Label Label+ | Shape Shape+ | Color Color+ | TextColor Color++{- | A dot label comes in three forms:+a primitive label (just a string) SLabel+a horizontally list of labels HLabel+and a vertically ordered list of labels VLabel+-}+data Label = SLabel String+ | HLabel [Label]+ | VLabel [Label]++-- | The shape of a dot node +data Shape = Rect+ | Circle+ | Oval+ | Triangle++-- | Colors +data Color = Red+ | Blue+ | Green+ | Yellow+ | Black+ | White+ | Gray++{- | Dot monad+While generating a dot file it is most convenient to do this in a monadic environment.+The inner state monad contains a supply that is used to generate unique identifiers.+In the inner Writer monad we store all the edges, the second writer monad contains+all the nodes. The error monad is used to register any eventual problems, while+preserving the state of the inner monads.+-} +type Dot = ErrorT FerryError (WriterT [Node] (WriterT [Edge] (State Int)))++-- | Generate a new node with the given nodeproperties, returns the new+-- fresh id in the Dot environment+node :: [NodeProp] -> Dot Id+node props = do+ i <- getFreshId+ addNode $ Node i props+ return i++-- | Generate an edge from arg1 to the nodes in arg2 and register it in the dot environment.+edge :: Id -> [Id] -> Dot ()+edge i is = addEdge $ Edge i is++-- | Given a dot environment generate either the error that the computation in the environment yields+-- or the resulting dot file as a string.+runDot :: Dot a -> Either FerryError String+runDot d = case r of+ Left err -> Left err+ Right _ -> Right $ dotFile ns es + where (((r, ns), es), _) = flip runState 0 $ runWriterT $ runWriterT $ runErrorT d++-- | Given a list of nodes and a list of edges generate a dot graph+dotFile :: [Node] -> [Edge] -> String+dotFile ns es = "digraph g {\nordering=out;" ++ concatMap dotNode ns ++ concatMap dotEdge es ++ "}"++-- | Generate the line that describes an edge in a dot file+dotEdge :: Edge -> String+dotEdge (Edge i ts) = concat [i ++ " -> " ++ t ++ ";\n" | t <- ts]++-- | Generate the line that describes a node in a dot file+dotNode :: Node -> String+dotNode (Node i props) = i ++ "[" ++ (concat $ L.intersperse "," $ map propsDot props) ++"];\n"++-- | Transform the properties into their dot representation+propsDot :: NodeProp -> String+propsDot (Shape Rect) = "shape=record" +propsDot (Shape Circle) = "shape=circle"+propsDot (Shape Oval) = "shape=ellipse"+propsDot (Shape Triangle) = "shape=triangle"+propsDot (Color Red) = "fillcolor=red,style=filled"+propsDot (Color Blue) = "fillcolor=blue,style=filled"+propsDot (Color Green) = "fillcolor=green,style=filled"+propsDot (Color Yellow) = "fillcolor=yellow,style=filled"+propsDot (Color Black) = "fillcolor=black,style=filled"+propsDot (Color White) = "fillcolor=white,style=filled"+propsDot (Color Gray) = "fillcolor=gray,style=filled"+propsDot (TextColor Red) = "color=red"+propsDot (TextColor Blue) = "color=blue"+propsDot (TextColor Green) = "color=green"+propsDot (TextColor Yellow) = "color=yellow"+propsDot (TextColor Black) = "color=black"+propsDot (TextColor White) = "color=white"+propsDot (TextColor Gray) = "color=gray"+propsDot (Label l) = "label=\"" ++ labelDot l ++ "\""++-- | Transform a label into its dot representation+labelDot :: Label -> String+labelDot (SLabel s) = escape s +labelDot (HLabel ls) = concat $ L.intersperse " | " $ map labelDot ls+labelDot (VLabel ls) = "{" ++ (concat $ L.intersperse " | " $ map (\l -> "{" ++ labelDot l ++ "}") ls) ++"}"++-- | Add an edge to the dot environment+addEdge :: Edge -> Dot ()+addEdge e = lift $ lift $ tell [e]++-- | Add a node to the dot environment+addNode :: Node -> Dot ()+addNode n = tell [n]++-- | Generate a fresh identifier+getFreshId :: Dot Id+getFreshId = do+ n <- get+ put $ n + 1+ return $ (:) 'n' $ show n++-- | Escape certain characters in a dot file +escape :: String -> String+escape (x:xs) = case x of+ '{' -> "\\{"+ '}' -> "\\}"+ '>' -> "\\>"+ '<' -> "\\<"+ _ -> [x]+ ++ escape xs+escape [] = []
+ src/Database/Ferry/Common/Render/Pretty.hs view
@@ -0,0 +1,26 @@+-- | Infrastructure for pretty printing+module Database.Ferry.Common.Render.Pretty where+ +import qualified Data.List as L++-- | Class for pretty printing a value of a.+class Pretty a where+ -- | pretty function transforms a value of a into a string with identation i.+ pretty :: a -> Int -> String++-- | Shorthand for pretty without the identation argument+prettyPrint :: Pretty a => a -> String+prettyPrint e = pretty e 0++-- | A newline followed by indenting n positions+newLine :: Int -> String+newLine n = "\n" ++ (take n $ repeat ' ')++-- | maps its first argument over the third, then intersperses+-- the result with the second argument, and finally concatenates everything.+mapIntersperseConcat :: (a -> [b]) -> [b] -> [a] -> [b]+mapIntersperseConcat f e l = concat $ L.intersperse e $ map f l++-- | Pretty print the values xs then intersperse with a comma and transform it into one string+intersperseComma :: Pretty a => [a] -> Int -> String+intersperseComma xs i = concat $ L.intersperse ", " $ map (flip pretty i) xs
+ src/Database/Ferry/Compiler.hs view
@@ -0,0 +1,16 @@+-- | The compiler interface+module Database.Ferry.Compiler+( module Database.Ferry.Compiler.Stages,+ FerryError(..), handleError,+ typedCoreToAlgebra,+ module Database.Ferry.Compiler.Types,+ backEndPipeline, backEndPipeline',+ executeStep +) where+ +import Database.Ferry.Compiler.Error.Error (FerryError (..), handleError)+import Database.Ferry.Compiler.Stages+import Database.Ferry.Compiler.Transform+import Database.Ferry.Compiler.Types+import Database.Ferry.Compiler.Pipeline+import Database.Ferry.Compiler.ExecuteStep
+ src/Database/Ferry/Compiler/Error/Error.hs view
@@ -0,0 +1,35 @@+-- | Internal compiler errors+module Database.Ferry.Compiler.Error.Error where++import Control.Monad.Error+import Database.Ferry.TypedCore.Data.Type++import Text.ParserCombinators.Parsec (ParseError())++-- | The FerryError datatype represents errors that occur during compilation+data FerryError = NoSuchFile String+ | ParserError ParseError+ | UnificationError FType FType+ | UnificationRecError [(RLabel, FType)] [(RLabel, FType)]+ | ClassAlreadyDefinedError String+ | SuperClassNotDefined String [String]+ | ClassNotDefined String+ | RecordDuplicateFields (Maybe String) [(RLabel, FType)]+ | NotARecordType FType+ | RecordWithoutI FType String+ | UnificationOfRecordFieldsFailed RLabel RLabel+ | UnificationFail RLabel RLabel+ | ProcessComplete+ deriving Show+ +-- | Just to satisfy the Error monad +instance Error FerryError where+ noMsg = error "This function should not be used Error.hs noMsg"+ strMsg = error "This function should not be used Error.hs strMsg"++-- | Print an error message +handleError :: FerryError -> IO ()+handleError ProcessComplete = return () -- Process complete just means everything was fine but the pipeline was ordered to stop early+handleError (ParserError e) = putStrLn $ show e+handleError e = putStrLn $ show e+
+ src/Database/Ferry/Compiler/ExecuteStep.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE FlexibleContexts #-}+{-| The compilation process is build out of small steps, this module provides the infrastructure+that executes one such step. -}+module Database.Ferry.Compiler.ExecuteStep (executeStep) where+ +import Database.Ferry.Compiler.Types++-- | Apply a compilation step to an expression of type a. The result of type b is returned in a phaseresult monad+executeStep :: CompilationStep a b -> a -> PhaseResult b+executeStep step i = do+ opts <- getConfig+ phaseHeader (stageName step) (stageMode step)+ b <- stageStep step i -- stageStep step gets the function that is to be applied this phase+ mapM_ (createArtefacts b) $ stageArtefacts step+ if (mode opts == stageMode step)+ then endProcess+ else return b++-- | The artefacts that can be generated by a compilationstep are generated by this function+createArtefacts :: b -> (Artefact, String, b -> ArtefactResult) -> PhaseResult ()+createArtefacts i (a, e, f) = do+ opts <- getConfig+ logMsg line+ logMsg $ "Artefact creation stage for: " ++ (show a)+ if elem a $ artefact opts+ then do + let file = case output opts of+ Nothing -> Nothing+ (Just file') -> Just $ file' ++ "." ++ e+ logMsg "Creating artefact"+ s <- artefactToPhaseResult $ f i+ addFile file s+ logMsg "Artefact creation done"+ logMsg line+ return ()+ else do+ logMsg "Artefact not required. Skipping artefact creation."+ logMsg line+ return ()++-- | Helper function to generate the phaseheader in the log +phaseHeader :: Name -> Mode -> PhaseResult ()+phaseHeader n s = do+ c <- getConfig+ logMsg line+ logMsg $ "Compiler stage: " ++ (show s)+ logMsg $ "Stage name: " ++ n+ logMsg "Compiling with the following options:"+ logMsg $ show c+ logMsg line+ return ()
+ src/Database/Ferry/Compiler/Pipeline.hs view
@@ -0,0 +1,27 @@+-- | Module describing the general core flow+module Database.Ferry.Compiler.Pipeline (backEndPipeline, backEndPipeline') where++import Database.Ferry.Compiler.Types+import Database.Ferry.Core.Data.Core (CoreExpr)+import qualified Database.Ferry.TypedCore.Data.TypedCore as T (CoreExpr)++import Database.Ferry.Compiler.Stages+ +-- | The compiler pipeline. The given Core AST is transformed dependent on the configuration of the Phaseresult+-- monad.+backEndPipeline :: CoreExpr -> PhaseResult ()+backEndPipeline c = typeInferPhase c >>=+ rewritePhase >>=+ boxingPhase >>=+ algebraPhase >>=+ xmlPhase >>+ return ()+ +-- | The compiler pipeline. Some tools might already provide a typed AST, is the same as the normal backEndPipeline+-- without type inferencing.+backEndPipeline' :: T.CoreExpr -> PhaseResult ()+backEndPipeline' c = rewritePhase c >>=+ boxingPhase >>=+ algebraPhase >>=+ xmlPhase >>+ return ()
+ src/Database/Ferry/Compiler/Stages.hs view
@@ -0,0 +1,10 @@+{-| Compiler stages of the backend-}+module Database.Ferry.Compiler.Stages (xmlPhase, boxingPhase, rewritePhase, + algebraPhase, typeInferPhase) where+ + +import Database.Ferry.Compiler.Stages.AlgebraToXMLStage+import Database.Ferry.Compiler.Stages.BoxingStage+import Database.Ferry.Compiler.Stages.RewriteStage+import Database.Ferry.Compiler.Stages.ToAlgebraStage+import Database.Ferry.Compiler.Stages.TypeInferStage
+ src/Database/Ferry/Compiler/Stages/AlgebraToXMLStage.hs view
@@ -0,0 +1,22 @@+{- | This module wraps the transform algebra into xml compilation stage+-}+module Database.Ferry.Compiler.Stages.AlgebraToXMLStage (xmlPhase) where+ +import Database.Ferry.Compiler.Types+import Database.Ferry.Compiler.ExecuteStep++import Database.Ferry.Algebra(AlgPlan, transform)++import Database.Ferry.TypedCore.Data.Type++xmlPhase :: (Qual FType, AlgPlan) -> PhaseResult String+xmlPhase (_ :=> t, p) = executeStep xmlStage $ case t of+ FList _ -> (True, p)+ _ -> (False, p)++xmlStage :: CompilationStep (Bool, AlgPlan) String+xmlStage = CompilationStep "ToXML" AlgebraXML step artefacts+ where+ step :: (Bool, AlgPlan) -> PhaseResult String+ step = return . show . transform + artefacts = [(XML, "xml", return)]
+ src/Database/Ferry/Compiler/Stages/BoxingStage.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE TemplateHaskell #-}+{- | This module wraps the boxing stage. Boxing is performed to ensure that nested lists are + handled in a separate table in the database. +-}+module Database.Ferry.Compiler.Stages.BoxingStage (boxingPhase) where+ +import Database.Ferry.Compiler.Types+import Database.Ferry.Compiler.ExecuteStep++import Database.Ferry.TypeSystem.Prelude+import Database.Ferry.TypedCore.Render.Dot+import Database.Ferry.Common.Render.Dot+ +import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Boxing.Boxing++import Database.Ferry.Impossible++boxingPhase :: CoreExpr -> PhaseResult CoreExpr+boxingPhase e = executeStep inferStage e++inferStage :: CompilationStep CoreExpr CoreExpr+inferStage = CompilationStep "Boxing" Boxing step artefacts+ where+ step :: CoreExpr -> PhaseResult CoreExpr+ step e = return $ runBoxing primitives e+ artefacts = [(DotBox ,"dot", \s -> return $ makeDot s)]+ +makeDot :: CoreExpr -> String+makeDot c = case runDot $ toDot c of+ Right s -> s+ Left _ -> $impossible
+ src/Database/Ferry/Compiler/Stages/RewriteStage.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE TemplateHaskell #-}+-- | This module wraps the rewrite stage, performing some rewrites on the ferry core AST.+module Database.Ferry.Compiler.Stages.RewriteStage (rewritePhase) where+ +import Database.Ferry.Compiler.Types+import Database.Ferry.Compiler.ExecuteStep++import Database.Ferry.TypedCore.Render.Dot+import Database.Ferry.Common.Render.Dot+ +import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Rewrite.OpRewrite++import Database.Ferry.Impossible++rewritePhase :: CoreExpr -> PhaseResult CoreExpr+rewritePhase e = executeStep inferStage e++inferStage :: CompilationStep CoreExpr CoreExpr+inferStage = CompilationStep "Rewrite" OpRewrite step artefacts+ where+ step :: CoreExpr -> PhaseResult CoreExpr+ step e = return $ rewrite e+ artefacts = [(DotRewrite ,"dot", \s -> return $ makeDot s)]+ +makeDot :: CoreExpr -> String+makeDot c = case runDot $ toDot c of+ Right s -> s+ Left _ -> $impossible
+ src/Database/Ferry/Compiler/Stages/ToAlgebraStage.hs view
@@ -0,0 +1,24 @@+-- | This module wraps the stage that translates ferry core into an algebraic graph+module Database.Ferry.Compiler.Stages.ToAlgebraStage (algebraPhase) where+ +import Database.Ferry.Compiler.Types+import Database.Ferry.Compiler.ExecuteStep++import Database.Ferry.Algebra(runGraph, initLoop, AlgPlan)++import Database.Ferry.TypedCore.Data.Instances()+import Database.Ferry.TypedCore.Convert.CoreToAlgebra+import Database.Ferry.TypedCore.Data.Type+ +import Database.Ferry.TypedCore.Data.TypedCore++algebraPhase :: CoreExpr -> PhaseResult (Qual FType, AlgPlan)+algebraPhase e = executeStep algebraStage e++algebraStage :: CompilationStep CoreExpr (Qual FType, AlgPlan)+algebraStage = CompilationStep "ToAlg" Algebra step artefacts+ where+ step :: CoreExpr -> PhaseResult (Qual FType, AlgPlan)+ step e = let eTy = typeOf e+ in return $ (eTy, runGraph initLoop $ coreToAlgebra e)+ artefacts = []
+ src/Database/Ferry/Compiler/Stages/TypeInferStage.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE TemplateHaskell #-}+-- | This module wraps the transformation stage from ferry core, to typed ferry core.+module Database.Ferry.Compiler.Stages.TypeInferStage (typeInferPhase) where+ +import Database.Ferry.Compiler.Types+import Database.Ferry.Compiler.ExecuteStep++import Database.Ferry.Common.Render.Pretty+import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.TypeSystem.Prelude+import Database.Ferry.TypedCore.Render.Dot+import Database.Ferry.Common.Render.Dot+import Database.Ferry.TypedCore.Convert.Specialize++import qualified Database.Ferry.Core.Data.Core as C+import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypeSystem.AlgorithmW++import Database.Ferry.Impossible++typeInferPhase :: C.CoreExpr -> PhaseResult CoreExpr+typeInferPhase e = executeStep inferStage e++inferStage :: CompilationStep C.CoreExpr CoreExpr+inferStage = CompilationStep "TypeInfer" TypeInfer step artefacts+ where+ step :: C.CoreExpr -> PhaseResult CoreExpr+ step e = let (res, _) = typeInfer primitives e+ in case res of+ Left err -> newError err+ Right expr -> return $ groupNSpecialize expr+ artefacts = [(Type ,"ty", \s -> return $ prettyPrint $ typeOf s)+ ,(DotType ,"dot", \s -> return $ makeDot s)]+ +makeDot :: CoreExpr -> String+makeDot c = case runDot $ toDot c of+ Right s -> s+ Left _ -> $impossible
+ src/Database/Ferry/Compiler/Transform.hs view
@@ -0,0 +1,24 @@+-- | This module is exposed in the library allowing other applications to compile typedCore to relational algebra+{-# LANGUAGE TemplateHaskell #-}+module Database.Ferry.Compiler.Transform (typedCoreToAlgebra) where+ +import Database.Ferry.Compiler.Pipeline (backEndPipeline')+import Database.Ferry.TypedCore.Data.TypedCore (CoreExpr)+import Database.Ferry.Compiler.Types+import Database.Ferry.Compiler.Error.Error+import Database.Ferry.Impossible++typedCoreToAlgebra :: CoreExpr -> String+typedCoreToAlgebra = compile defaultConfig ++-- | The compiler pipeline+-- Note that there should be a monadic style for handling all the steps in the pipeline+compile :: Config -> CoreExpr -> String+compile opts inp = do+ let (r, _, f) = runPhase opts $ backEndPipeline' inp + case (r, f) of+ (Right (), [(_, o)]) -> o+ (Left ProcessComplete, [(_, o)]) -> o+ (Left err, _) -> error $ show err+ _ -> $impossible+
+ src/Database/Ferry/Compiler/Types.hs view
@@ -0,0 +1,164 @@+{-# LANGUAGE FlexibleContexts #-}+{-| Types used by the compiler infrastructure-}+module Database.Ferry.Compiler.Types where+ +import Control.Monad.Error+import Control.Monad.Writer+import Control.Monad.Reader++import Database.Ferry.Compiler.Error.Error++-- | The config datatype is used to store program flags given by the user +-- The compiler can be put in a 'Mode' that determines what sort of+-- result the compilation process will result in.+-- The 'Input' element is set to specify whether a file should be compiled or +-- input from the stdin+-- The debug component is set to switch on debugging mode, debugging mode+-- results in log information on the stdin and possibly extra compiler artifacts.+data Config = Config {+ mode :: Mode,+ logFile :: Maybe String,+ output :: Maybe String,+ input :: Input,+ artefact :: [Artefact],+ debug :: Bool+ }+ deriving Show++-- | The modes that are supported by the compiler.+-- run ferryc -h to see a list of all options+data Mode = Read+ | Parse -- ^ Parse mode will stop the compiler after the parsing phase+ | Normalise + | Transform+ | TypeInfer+ | OpRewrite+ | Boxing+ | Algebra+ | AlgebraXML+ deriving (Show, Eq)+ +data Artefact = Echo -- ^ Echo mode prints the given input to the console+ | PrettyAST -- ^ Pretty mode parses the given input and pretty prints the result+ | PrettyNormalAST+ | PrettyCore+ | DotAST+ | DotCore+ | DotType+ | DotRewrite+ | DotBox+ | DotAlg+ | XML+ | Type+ deriving (Show, Eq)++-- All possible artefacts+allArtefacts :: [Artefact]+allArtefacts = [Echo, PrettyAST, PrettyCore, DotAST, DotCore, DotType, DotBox, DotAlg, XML]++-- | The input mode determines whether the source program is given through a file or via stdin+data Input = File String-- ^ File mode, the program is read from a file + | Arg -- ^ Argument mode, the program is given as input directly+ deriving (Show, Eq)++-- | The default configuration for the compiler+defaultConfig :: Config+defaultConfig = Config {+ -- Standard 'Mode' is set to Full+ mode = AlgebraXML,+ logFile = Nothing,+ output = Nothing, + -- By default the program is given through a File+ input = Arg,+ -- Standard output is the empty list, denoting regular compilation proces+ artefact = [XML], + -- Debug turned of by default+ debug = False + }++-- | The results of artefact generation are all collected in a reader monad+-- The final result is written to disk or screen when compilation has succeeded+type ArtefactResult = Reader Config String++-- | Result of a compilation phase.+-- The error monad is used in case something went wrong during compilation+-- The first writer monad is used for logging purposes.+-- The second writer monad is used to store the artefacts generated by the compiler+-- And the reader monad stores the compiler configuration +type PhaseResult r = ErrorT FerryError (WriterT Log (WriterT [File] (Reader Config))) r++-- | Name of an artefact file+type FileName = String++-- | Artefact file, the first element represents the output file, in case of nothing output is given+-- on stdout. The second component is the file content.+type File = (Maybe FileName, String)++-- | Compilationstep datatype.+-- A compilation step is a record containg a description (stageName field),+-- the internal mode name (stageMode field),+-- the actual stage computation (stageStep field) that transforms element of type a into a PhaseResult of type b+-- and stage artefact generators, a list of function generating artefacts (stageArtefacts field).+data CompilationStep a b = CompilationStep { + stageName :: Name, + stageMode :: Mode,+ stageStep :: a -> PhaseResult b,+ stageArtefacts :: [(Artefact, String, b -> ArtefactResult)]+ }++-- | Type synonym for a stage name type+type Name = String++-- | Every stage has a stage number+type Stage = Int++-- | The compilation log is just a string+type Log = [String]++-- | Lift the result of generating an artefact into the overall phase result type+artefactToPhaseResult :: ArtefactResult -> PhaseResult String+artefactToPhaseResult r = lift $ lift $ lift r++-- | Get the compiler configuration+getConfig :: PhaseResult Config+getConfig = ask++-- | Get the current log from a phaseresult+getLog :: Config -> PhaseResult r -> Log+getLog c n = (\(_, l, _) -> l) $ runPhase c n++-- | Get the artefacts from the phaseresult +getFiles :: Config -> PhaseResult r -> [File]+getFiles c n = (\(_, _, f) -> f) $ runPhase c n ++-- | Execute a phaseresult under a given configuration,, resulting in triple of:+-- 1.) An error or the result+-- 2.) The compilation log+-- 3.) The generated artefacts+runPhase :: Config -> PhaseResult r -> (Either FerryError r, Log, [File])+runPhase c n = (\((r, l), f) -> (r, l, f)) $ flip runReader c $ runWriterT $ runWriterT $ runErrorT n++-- | Throw an error+newError :: FerryError -> PhaseResult r+newError e = ErrorT $ return $ Left e++-- | Final log message when end of compilation is reached+endProcess :: PhaseResult b+endProcess = do+ logMsg line+ logMsg "Reached compilation target"+ logMsg "Quiting compilation"+ logMsg line+ newError ProcessComplete++-- | Seperator line for logging+line :: String+line = "--------------------------------------------------"++-- | Log the message t+logMsg :: (MonadWriter [t] m) => t -> m ()+logMsg s = tell [s]++-- | Add the given file with contents to the phaseresult.+addFile :: Maybe FileName -> String -> PhaseResult ()+addFile n c = lift $ lift $ tell [(n, c)]
+ src/Database/Ferry/Core/Data/Core.hs view
@@ -0,0 +1,59 @@+{-| Untyped core data type -}+{-# LANGUAGE GADTs #-}+module Database.Ferry.Core.Data.Core where++import Database.Ferry.Common.Data.Base++-- | An identifier is represented by a string+type Ident = String++-- | Operator constructor+data Op where+ Op :: String -> Op++-- | Datatype for building untyped core ASTs+data CoreExpr where+ BinOp :: Op -> CoreExpr -> CoreExpr -> CoreExpr+-- UnaOp :: Op -> CoreExpr -> CoreExpr+ Constant :: Const -> CoreExpr+ Var :: String -> CoreExpr+ App :: CoreExpr -> Param -> CoreExpr+ Let :: String -> CoreExpr -> CoreExpr -> CoreExpr+ Rec :: [RecElem] -> CoreExpr+ Cons :: CoreExpr -> CoreExpr -> CoreExpr+ Nil :: CoreExpr+ Elem :: CoreExpr -> String -> CoreExpr+ Table :: String -> [Column] -> [Key] -> CoreExpr+ If :: CoreExpr -> CoreExpr -> CoreExpr -> CoreExpr++-- | Record elements+data RecElem where+ RecElem :: String -> CoreExpr -> RecElem+ +-- | Function arguments+-- In future, that is when defunctionalisation is implemented function arguments should just be expressions.+data Param where+ ParExpr :: CoreExpr -> Param+ ParAbstr :: [String] -> CoreExpr -> Param+{- +-- | Patterns +data Pattern where+ PVar :: String -> Pattern+ Pattern :: [String] -> Pattern+-}+ +-- | Database table column+data Column where+ Column :: String -> Type -> Column++-- | Database column type +data Type+ = TInt + | TFloat + | TString + | TBool+ | TUnit++-- | Database table key +data Key where+ Key :: [String] -> Key
+ src/Database/Ferry/Core/Render/Dot.hs view
@@ -0,0 +1,97 @@+-- | Provides Dotify instance for untyped core +module Database.Ferry.Core.Render.Dot() where++import Database.Ferry.Common.Render.Dot +import Database.Ferry.Core.Data.Core+import Database.Ferry.Common.Data.Base+import Database.Ferry.Core.Render.Pretty++import qualified Data.List as L+++instance Dotify CoreExpr where+ dot e = runDot $ toDot e++-- | Transform core expression to dot environment+toDot :: CoreExpr -> Dot Id+toDot (BinOp o e1 e2) = do+ id1 <- toDot e1+ id2 <- toDot e2+ let o' = (\(Op op) -> op) o+ nId <- node [Label $ SLabel o', Color Green, Shape Circle]+ edge nId [id1, id2]+ return nId+toDot (Constant c) = let s = toString c+ in node [Label $ SLabel s, Color Yellow, Shape Triangle]+toDot (Var i) = node [Label $ SLabel i, Color Red, Shape Triangle]+toDot (App c ps) = do+ nId <- node [Label $ SLabel "$", Color Green, Shape Circle]+ fId <- toDot c+ pIds <- paramToDot ps+ edge nId [fId, pIds]+ return nId+toDot (Let s e1 e2) = do+ nId <- node [Label $ SLabel "Let", Color Blue, Shape Rect]+ id0 <- node [Label $ SLabel s, Color Red, Shape Rect, TextColor White]+ id1 <- toDot e1+ id2 <- toDot e2+ edge nId [id0, id1, id2]+ return nId+toDot (Rec es) = do+ nId <- node [Label $ SLabel "Rec", Color Blue, Shape Oval]+ eIds <- mapM recToDot es+ edge nId eIds+ return nId+toDot (Cons e1 e2) = do+ nId <- node [Label $ SLabel "Cons", Color Blue, Shape Oval]+ eIdh <- toDot e1+ eIdt <- toDot e2+ edge nId [eIdh, eIdt]+ return nId+toDot (Nil) = node [Label $ SLabel "Nil", Color Blue, Shape Oval]+toDot (Elem c s) = do+ nId <- node [Label $ SLabel ".", Color Green, Shape Circle]+ sId <- node [Label $ SLabel s, Color Red, Shape Triangle]+ cId <- toDot c+ edge nId [cId, sId]+ return nId+toDot (Table n cs ks) = let label = VLabel $ ((HLabel [SLabel "Table:", SLabel n])+ : [HLabel [SLabel $ n' ++ "::", SLabel $ prettyTy t ] | (Column n' t) <- cs])+ ++ [SLabel $ keyToString k | k <- ks]+ in node [Shape Rect, Label label, Color Yellow]+toDot (If e1 e2 e3) = do+ nId <- node [Label $ SLabel "If", Color Blue, Shape Circle]+ eId1 <- toDot e1+ eId2 <- toDot e2+ eId3 <- toDot e3+ edge nId [eId1, eId2, eId3]+ return nId+ +-- | Convert function parameters to dot representations+paramToDot :: Param -> Dot Id+paramToDot (ParExpr e) = toDot e+paramToDot (ParAbstr p e) = do+ nId <- node [Label $ SLabel "\\ ->", Color Blue, Shape Circle]+ pId <- node [Label $ SLabel (concat $ L.intersperse " " p), Color Red, Shape Triangle]+ eId <- toDot e+ edge nId [pId, eId]+ return nId++{-+-- | Convert a pattern to a dot node +patToDot :: Pattern -> Dot Id+patToDot (PVar s) = node [Label $ SLabel s, Color Red, Shape Triangle]+patToDot (Pattern s) = node [Label $ SLabel $ "(" ++ (concat $ L.intersperse ", " s) ++ ")", Color Red, Shape Triangle]+-}++-- | Convert a record element to a dot node+recToDot :: RecElem -> Dot Id+recToDot (RecElem s e) = do+ nId <- node [Label $ SLabel s, Color Red, Shape Oval]+ eId <- toDot e+ edge nId [eId]+ return nId++-- | Generate a string representation of a database key+keyToString :: Key -> String+keyToString (Key ks) = "(" ++ (concat $ L.intersperse ", " ks) ++ ")"
+ src/Database/Ferry/Core/Render/Pretty.hs view
@@ -0,0 +1,15 @@+-- | Pretty print instance for database types+module Database.Ferry.Core.Render.Pretty where++import Database.Ferry.Core.Data.Core+import Database.Ferry.Common.Render.Pretty++instance Pretty Type where+ pretty a _ = prettyTy a++prettyTy :: Type -> String+prettyTy TUnit = "()"+prettyTy TInt = "Int"+prettyTy TFloat = "Float" +prettyTy TString = "String" +prettyTy TBool = "Bool"
+ src/Database/Ferry/Impossible.hs view
@@ -0,0 +1,11 @@+-- | Utility module for reporting impossible events+module Database.Ferry.Impossible (impossible) where++import qualified Language.Haskell.TH as TH++impossible :: TH.ExpQ+impossible = do+ loc <- TH.location+ let pos = (TH.loc_filename loc, fst (TH.loc_start loc), snd (TH.loc_start loc))+ let message = "ferry: Impossbile happend at " ++ show pos+ return (TH.AppE (TH.VarE (TH.mkName "error")) (TH.LitE (TH.StringL message)))
+ src/Database/Ferry/Syntax.hs view
@@ -0,0 +1,16 @@+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-| Everything related to untyped core -}+module Database.Ferry.Syntax {-# DEPRECATED "Use Database.Ferry.SyntaxTyped instead of this module. This module will not be available in future FerryCore releases." #-}+(+Ident,+Identifier, Const (..), VarContainer(..),+Op (..), CoreExpr (..), RecElem (..), Param (..), Column (..), Key (..), Type(..),+Dotify(..),+module Database.Ferry.Common.Render.Pretty+)+where+import Database.Ferry.Common.Data.Base +import Database.Ferry.Core.Data.Core (Op (..), CoreExpr (..), RecElem (..), Param (..), Column (..), Key (..), Ident, Type(..))+import Database.Ferry.Core.Render.Dot()+import Database.Ferry.Common.Render.Dot(Dotify(..))+import Database.Ferry.Common.Render.Pretty
+ src/Database/Ferry/SyntaxTyped.hs view
@@ -0,0 +1,16 @@+{-| Everything related to typed core-}+module Database.Ferry.SyntaxTyped +(+Ident,+Identifier, Const (..),+Op (..), CoreExpr (..), RecElem (..), Param (..), Column (..), Key (..),+int, float, string, bool, list, var, rec, fn, genT, (.->), TyScheme (..), Qual (..), Pred (..), FType (..), RLabel (..), FTFn (..), HasType, typeOf,+Dotify(..)+)+where+import Database.Ferry.Common.Data.Base +import Database.Ferry.TypedCore.Data.TypedCore (Op (..), CoreExpr (..), RecElem (..), Param (..), Column (..), Key (..), Ident)+import Database.Ferry.TypedCore.Data.Type (int, float, string, bool, list, var, rec, fn, genT, (.->), TyScheme (..), Qual (..), Pred (..), FType (..), RLabel (..), FTFn (..), HasType, typeOf)+import Database.Ferry.TypedCore.Data.Instances() +import Database.Ferry.TypedCore.Render.Dot()+import Database.Ferry.Common.Render.Dot
+ src/Database/Ferry/TypeSystem/AlgorithmW.hs view
@@ -0,0 +1,220 @@+{-| Infer types for a program, transform an untyped core AST into a typed core AST.+Standard Algorithm W, with some modifications to deal with records.-}+module Database.Ferry.TypeSystem.AlgorithmW (typeInfer) where++import Database.Ferry.TypeSystem.Types +import qualified Database.Ferry.Core.Data.Core as C+import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.TypedCore.Data.Substitution +import Database.Ferry.Compiler.Error.Error+import Database.Ferry.Common.Data.Base (Const (..)) +import Database.Ferry.TypeSystem.Unification+import Database.Ferry.TypeSystem.ContextReduction+++import qualified Data.Set as S+import qualified Data.List as L+import qualified Data.Map as M++import Control.Applicative hiding (Const(..))+import Control.Monad.Reader+import Control.Monad.Error++typeInfer :: TyEnv -> C.CoreExpr -> (Either FerryError CoreExpr, Subst)+typeInfer gam c = runAlgW gam $ do + e <- algW c+ -- (p, s@(Forall _ t)) <- gen $ pure $ typeOf e+ let (q :=> t) = typeOf e+ q' <- consistents $ pure q+ let (qs, q'' :=> _t') = reduce (q' :=> t) M.empty+ qual <- mergeQuals qs q''+ applySubst $ setType (qual :=> t) e+ --pure e+ +algW :: C.CoreExpr -> AlgW CoreExpr+algW (C.Constant c) = Constant <$> typeOfConst c <*> pure c+algW (C.Var x) = Var <$> (inst $ lookupVariable x) <*> pure x+algW (C.Let x c1 c2) = do+ c1' <- algW c1+ (p, ts@(Forall _ _ qt)) <- gen $ pure $ typeOf c1'+ let c1'' = setType qt c1'+ c2' <- addToEnv x ts (algW c2)+ let (q2 :=> t2) = typeOf c2'+ q <- mergeQuals q2 p+ applySubst $ Let (q :=> t2) x c1'' c2' +algW (C.Nil) = Nil <$> liftM (\v -> [] :=> (list $ FVar v)) freshTyVar+algW (C.Cons c1 c2) = do+ c1' <- algW c1+ c2' <- algW c2+ let (q1 :=> t1) = typeOf c1'+ let (q2 :=> t2) = typeOf c2'+ unify t2 $ FList t1+ q <- mergeQuals q1 q2+ applySubst $ Cons (q :=> t2) c1' c2'+algW (C.If c1 c2 c3) = do+ c1' <- algW c1+ c2' <- algW c2+ c3' <- algW c3+ let (q1 :=> t1) = typeOf c1'+ let (q2 :=> t2) = typeOf c2'+ let (q3 :=> t3) = typeOf c3' + s <- getSubst+ unify (apply s $ t1) FBool+ s' <- getSubst+ unify (apply s' $ t2) (apply s' $ t3) + q <- mergeQuals' [q1, q2, q3]+ applySubst $ If (q :=> t2) c1' c2' c3'+algW (C.Table n cs ks) = let recTys = L.sortBy (\(n1, _t1) (n2, _t2) -> compare n1 n2) $ map columnToRecElem cs+ in if length (uniqueKeys recTys) == length recTys + then applySubst $ Table ([] :=> (list $ FRec recTys)) n (map columnToTyColumn cs) (map keyToTyKey ks)+ else throwError $ RecordDuplicateFields (Just n) $ map columnToRecElem cs+algW (C.Elem e i) = do+ fresh <- liftM FVar freshTyVar+ c1' <- algW e+ let (q1 :=> t1) = typeOf c1'+ case t1 of+ (FVar _v) -> do + q <- insertQual (Has t1 (RLabel i) fresh) q1 + applySubst $ Elem (q :=> fresh) c1' i+ (FRec els) -> case lookup (RLabel i) els of+ Nothing -> throwError $ RecordWithoutI t1 i+ (Just a) -> applySubst $ Elem (q1 :=> a) c1' i+ _ -> throwError $ NotARecordType t1+algW (C.Rec elems) = do+ els <- recElemsToTyRecElems elems+ let (qs, nt) = foldr (\(RecElem (q :=> t) n _) (qs', nt') -> (q:qs', (RLabel n, t):nt')) ([], []) els+ let t = FRec $ L.sortBy (\(n1, _t1) (n2, _t2) -> compare n1 n2) nt+ q <- mergeQuals' qs+ if (length (uniqueKeys nt) == length nt) + then applySubst $ Rec (q :=> t) els+ else throwError $ RecordDuplicateFields Nothing nt+algW (C.BinOp (C.Op o) e1 e2) = do+ ot <- inst $ lookupVariable o+ let (q :=> FFn ot1 (FFn ot2 otr)) = ot+ e1' <- algW e1+ e2' <- algW e2+ let (q1 :=> t1) = typeOf e1'+ (q2 :=> t2) = typeOf e2'+ unify t1 ot1+ unify t2 ot2+ q' <- mergeQuals' [q, q1, q2] + applySubst $ BinOp (q' :=> otr) (Op o) e1' e2'+{- algW (C.UnaOp (C.Op o) e1) = + do+ ot <- inst $ lookupVariable o+ let (q :=> FFn ot1 otr) = ot+ e1' <- algW e1+ let (q1 :=> t1) = typeOf e1'+ unify t1 ot1+ q' <- mergeQuals q q1 + applySubst $ UnaOp (q :=> otr) (Op o) e1' -}+algW (C.App e arg) = do+ ar <- liftM FVar freshTyVar+ e' <- algW e+ arg' <- algWArg arg+ let (qt1 :=> t1) = typeOf e'+ (qta :=> ta) = typeOf arg'+ unify t1 (FFn ta ar)+ q1 <- applySubst qt1+ q2 <- applySubst qta+ + rqt <- (mergeQuals q1 q2)+ t <- applyS $ pure (rqt :=> ar)+ applySubst $ App t e' arg'+ ++algWArg :: C.Param -> AlgW Param+algWArg (C.ParExpr e) = do+ e' <- algW e+ applySubst $ ParExpr (typeOf e') e' +algWArg (C.ParAbstr p e) = do+ let vars' = p+ bindings <- foldr (\v r -> do+ t <- liftM (\var' -> [] :=> FVar var') freshTyVar+ r' <- r+ return $ (v, t):r' + ) (pure []) vars'+ e' <- foldr (\(v, t) r -> addToEnv v (Forall 0 0 t) r) (algW e) bindings+ let (q :=> rt) = typeOf e'+ let t = q :=> (foldr (\(_, _ :=> ty) r -> FFn ty r) rt bindings) + applySubst $ ParAbstr t vars' e'+ +{-+toPattern :: [String] -> Pattern+toPattern [x] = PVar x+toPattern xs = Pattern xs+ +getVars :: C.Pattern -> [String]+getVars (C.PVar v) = [v]+getVars (C.Pattern p) = p +-} +uniqueKeys :: Eq k => [(k, a)] -> [(k, a)]+uniqueKeys l1 = L.nubBy (\(k1, _) (k2, _) -> k1 == k2) l1 ++recElemsToTyRecElems :: [C.RecElem] -> AlgW [RecElem]+recElemsToTyRecElems (x:xs) = do+ x' <- recElemToTyRecElem x+ xs' <- recElemsToTyRecElems xs+ pure (x':xs')+recElemsToTyRecElems [] = pure []++recElemToTyRecElem :: C.RecElem -> AlgW RecElem+recElemToTyRecElem (C.RecElem s e) = do+ e' <- algW e+ let t = typeOf e'+ applySubst $ RecElem t s e' + + +columnToTyColumn :: C.Column -> Column+columnToTyColumn (C.Column s t) = Column s $ typeToFType t++columnToRecElem :: C.Column -> (RLabel, FType)+columnToRecElem (C.Column s t) = (RLabel s, typeToFType t)++typeToFType :: C.Type -> FType+typeToFType C.TInt = FInt+typeToFType C.TFloat = FFloat+typeToFType C.TString = FString+typeToFType C.TBool = FBool+typeToFType C.TUnit = FUnit ++keyToTyKey :: C.Key -> Key+keyToTyKey (C.Key k) = Key k ++typeOfConst :: Const -> AlgW (Qual FType)+typeOfConst (CInt _) = pure $ [] :=> FInt+typeOfConst (CFloat _) = pure $ [] :=> FFloat+typeOfConst (CBool _) = pure $ [] :=> FBool+typeOfConst (CString _) = pure $ [] :=> FString+typeOfConst (CUnit) = pure $ [] :=> FUnit+++gen :: AlgW (Qual FType) -> AlgW ([Pred], TyScheme)+gen s = do+ s' <- s+ gam <- getGamma+ let freeInT = ftv s'+ let freeInGam = ftv gam+ let freeRInT = frv s'+ let freeRInGam = frv gam+ let quant = S.toList $ freeInT S.\\ freeInGam+ let quantR = S.toList $ freeRInT S.\\ freeRInGam+ let substs = zip quant [FGen i | i <- [1..]]+ let substsR = zip quantR [RGen i | i <- [1..]]+ qualT <- foldr (\(i, q) -> localAddSubstitution (FVar i) q) (applyS $ pure s') substs+ qualR <- foldr (\(i, q) -> localAddRecSubstitution (RVar i) q) (applyS $ pure qualT) substsR+ let (qg, qt) = reduce qualR M.empty+ return $ (qg, Forall (length substs) (length substsR) $ qt)+ +inst :: AlgW TyScheme -> AlgW (Qual FType)+inst s = do+ s' <- s+ case s' of+ Forall 0 0 t -> applyS $ pure t+ Forall 0 t ty -> do+ freshVar <- freshTyVar+ localAddRecSubstitution (RGen t) (RVar freshVar) (inst $ pure $ Forall 0 (t - 1) ty)+ Forall i t ty -> do+ freshVar <- freshTyVar+ localAddSubstitution (FGen i) (FVar freshVar) (inst $ pure $ Forall (i-1) t ty)
+ src/Database/Ferry/TypeSystem/ContextReduction.hs view
@@ -0,0 +1,38 @@+module Database.Ferry.TypeSystem.ContextReduction where+ +import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.TypedCore.Data.TypeClasses+import Database.Ferry.TypedCore.Data.Instances()++import qualified Data.List as L+import qualified Data.Set as S++reduce :: Qual FType -> ClassEnv -> ([Pred], Qual FType)+reduce (preds :=> tau) _ = (gamPreds, tyPreds :=> tau)+ where+ (tyPreds, gamPreds) = L.partition hasQVar (simplifyPreds $ foldr filterImpossiblePreds [] recPr)+ (recPr, _classPr) = L.partition (\p -> case p of+ Has _ _ _ -> True+ _ -> False) preds++simplifyPreds :: [Pred] -> [Pred]+simplifyPreds ps = foldr (\x l -> (flatten x) : l) [] groups+ where+ flatten x = case x of+ [x'] -> x'+ _ -> error "Multiple types for one field"+ groups = map L.nub $ L.groupBy (\c1 c2 -> case (c1, c2) of+ ((Has f1 r1 _), (Has f2 r2 _)) -> f1 == f2 && r1 == r2+ _ -> error "Wrong type of predicate") ps+++filterImpossiblePreds :: Pred -> [Pred] -> [Pred]+filterImpossiblePreds p@(Has (FVar v) _ t) ps = case S.member v (ftv t) of+ True -> error "infinite type in record"+ False -> p:ps+filterImpossiblePreds p@(Has (FRec _) _ (FVar _)) ps = (p:ps)+ +filterImpossiblePreds p@(Has (FRec rs) f t) ps = case L.lookup f rs of+ Nothing -> error "record does not contain file"+ (Just t2) -> if t == t2 then ps else error $ show p ++ "incompatable types"+filterImpossiblePreds _ _ = error "Not a record type"
+ src/Database/Ferry/TypeSystem/Prelude.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE TemplateHaskell #-}+module Database.Ferry.TypeSystem.Prelude where++import Database.Ferry.Impossible +import Database.Ferry.TypedCore.Data.TypeClasses+import Database.Ferry.TypedCore.Data.Type++import qualified Data.Map as M++baseEnv :: ClassEnv+baseEnv = case addAll emptyClassEnv of+ Right a -> a+ _ -> $impossible+ where+ addAll =+ do+ addBaseClasses <:> addBaseInstances+ addBaseClasses =+ addClass "Eq" []+ <:> addClass "Num" []+ <:> addClass "Ord" ["Eq"]+ addBaseInstances =+ addInstance [] (IsIn "Eq" FInt)+ <:> addInstance [] (IsIn "Eq" FFloat)+ <:> addInstance [] (IsIn "Eq" FBool)+ <:> addInstance [] (IsIn "Eq" FString)+ <:> addInstance [IsIn "Eq" $ FVar "a"] (IsIn "Eq" $ FList $ FVar "a")+ <:> addInstance [] (IsIn "Num" FFloat)+ <:> addInstance [] (IsIn "Num" FInt)+ <:> addInstance [] (IsIn "Ord" FFloat)+ <:> addInstance [] (IsIn "Ord" FBool)+ <:> addInstance [] (IsIn "Ord" FString)+ <:> addInstance [IsIn "Ord" $ FVar "a"] (IsIn "Ord" $ FList $ FVar "a")+ +primitives :: TyEnv+primitives = M.fromList $+ [("+", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) (FGen 1)))+ ,("-", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) (FGen 1)))+ ,("*", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) (FGen 1)))+ ,("/", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) (FGen 1)))+ ,("%", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) (FGen 1)))+ ,("^", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) (FGen 1)))+ ,("max", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> FGen 1 .-> FGen 1 .-> FGen 1)+ ,("min", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> FGen 1 .-> FGen 1 .-> FGen 1)+ ,("sum", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> (list $ genT 1) .-> genT 1)+ ,("product", Forall 1 0 $ [IsIn "Num" (FGen 1)] :=> (list $ genT 1) .-> genT 1)+ ,("maximum", Forall 1 0 $ [IsIn "Ord" (FGen 1)] :=> (list $ genT 1) .-> genT 1)+ ,("minimum", Forall 1 0 $ [IsIn "Ord" (FGen 1)] :=> (list $ genT 1) .-> genT 1)+ ,("==", Forall 1 0 $ [IsIn "Eq" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) bool))+ ,("!=", Forall 1 0 $ [IsIn "Eq" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) bool))+ ,("<=", Forall 1 0 $ [IsIn "Ord" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) bool))+ ,(">=", Forall 1 0 $ [IsIn "Ord" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) bool))+ ,("<", Forall 1 0 $ [IsIn "Ord" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) bool))+ ,(">", Forall 1 0 $ [IsIn "Ord" (FGen 1)] :=> FFn (FGen 1) (FFn (FGen 1) bool))+ ,("not", Forall 0 0 $ [] :=> bool .-> bool)+ ,("and", Forall 0 0 $ [] :=> list bool .-> bool)+ ,("or", Forall 0 0 $ [] :=> list bool .-> bool)+ ,("&&", Forall 0 0 $ [] :=> bool .-> bool .-> bool)+ ,("||", Forall 0 0 $ [] :=> bool .-> bool .-> bool)+ ,("minP", Forall 1 0 $ [] :=> (list $ genT 1) .-> (list $ genT 1) .-> FInt)+ ,("count", Forall 1 0 $ [] :=> (list $ genT 1) .-> FInt)+ ,("length", Forall 1 0 $ [] :=> (list $ genT 1) .-> FInt)+ ,("all", Forall 0 0 $ [] :=> (list bool) .-> bool)+ ,("map", Forall 2 0 $ [] :=> (genT 1 .-> genT 2) .-> list (genT 1) .-> list (genT 2))+ ,("concatMap", Forall 2 0 $ [] :=> (genT 1 .-> list (genT 2)) .-> list (genT 1) .-> list (genT 2))+ ,("zipWith", Forall 3 0 $ [] :=> (genT 1 .-> genT 2 .-> genT 3) .-> list (genT 1) .-> list (genT 2) .-> list (genT 3))+ ,("takeWhile", Forall 1 0 $ [] :=> (genT 1 .-> bool) .-> (list $ genT 1) .-> (list $ genT 1))+ ,("dropWhile", Forall 1 0 $ [] :=> (genT 1 .-> bool) .-> (list $ genT 1) .-> (list $ genT 1))+ ,("concat", Forall 1 0 $ [] :=> (list $ list $ genT 1) .-> (list $ genT 1))+ ,("single", Forall 1 0 $ [] :=> (list $ genT 1) .-> genT 1)+ ,("filter", Forall 1 0 $ [] :=> (genT 1 .-> bool) .-> (list $ genT 1) .-> (list $ genT 1))+ ,("lookup", Forall 2 0 $ [IsIn "Eq" (genT 1)] :=> list (rec [(RLabel "1", genT 1), (RLabel "2", genT 2)]) .-> genT 1 .-> genT 2)+ ,("length", Forall 1 0 $ [] :=> (list $ genT 1) .-> FInt)+ ,("splitAt", Forall 1 0 $ [] :=> int .-> (list $ genT 1) .-> rec [(RLabel "1", genT 1), (RLabel "2", genT 1)])+ ,("fst", Forall 2 0 $ [] :=> rec [(RLabel "1", genT 1), (RLabel "2", genT 2)] .-> genT 1)+ ,("snd", Forall 2 0 $ [] :=> rec [(RLabel "1", genT 1), (RLabel "2", genT 2)] .-> genT 2)+ ,("the", Forall 1 0 $ [] :=> (list $ genT 1) .-> genT 1)+ ,("head", Forall 1 0 $ [] :=> (list $ genT 1) .-> genT 1)+ ,("take", Forall 1 0 $ [] :=> FInt .-> (list $ genT 1) .-> (list $ genT 1))+ ,("drop", Forall 1 0 $ [] :=> FInt .-> (list $ genT 1) .-> (list $ genT 1))+ ,("reverse", Forall 1 0 $ [] :=> (list $ genT 1) .-> (list $ genT 1))+ ,("index", Forall 1 0 $ [] :=> (list $ genT 1) .-> FInt .-> genT 1)+ ,("last", Forall 1 0 $ [] :=> (list $ genT 1) .-> (list $ genT 1))+ ,("tail", Forall 1 0 $ [] :=> (list $ genT 1) .-> (list $ genT 1))+ ,("init", Forall 1 0 $ [] :=> (list $ genT 1) .-> (list $ genT 1))+ ,("null", Forall 1 0 $ [] :=> (list $ genT 1) .-> bool)+ ,("nub", Forall 1 0 $ [] :=> (list $ genT 1) .-> (list $ genT 1))+ ,("integerToDouble", Forall 0 0 $ [] :=> int .-> float)+ ,("sortWith", Forall 2 0 $ [IsIn "Ord" (FGen 2)] :=> (genT 1 .-> genT 2) .-> (list $ genT 1) .-> (list $ genT 1))+ ,("groupByN", Forall 3 0 $ [] :=> (genT 1 .-> genT 2) .-> (genT 1 .-> genT 3) .-> list (genT 1) .-> (list $ FTF Tr (genT 2)))+ ,("groupBy'", Forall 3 1 $ [] :=> (genT 1 .-> genT 2) .-> (genT 1 .-> genT 3) .-> list (genT 1) .-> (list $ list $ genT 2))+ ,("groupBy1", Forall 3 1 $ [] :=> (genT 1 .-> rec [(RGen 1 ,genT 2)]) .-> (genT 1 .-> genT 3) .-> list (genT 1) .-> (list $ rec [(RGen 1 , list $ genT 2)]))+ ,("groupBy2", Forall 4 2 $ [] :=> (genT 1 .-> rec [(RGen 1 ,genT 2), (RGen 2, genT 4)]) .-> (genT 1 .-> genT 3) .-> list (genT 1) .-> (list $ rec [(RGen 1 , list $ genT 2), (RGen 2, list $ genT 4)]))+ ,("groupBy3", Forall 5 3 $ [] :=> (genT 1 .-> rec [(RGen 1 ,genT 2), (RGen 2, genT 4), (RGen 3, genT 5)]) .-> (genT 1 .-> genT 3) .-> list (genT 1) .-> (list $ rec [(RGen 1 , list $ genT 2), (RGen 2, list $ genT 4), (RGen 3, list $ genT 5)]))+ ,("groupBy4", Forall 6 4 $ [] :=> (genT 1 .-> rec [(RGen 1 ,genT 2), (RGen 2, genT 4), (RGen 3, genT 5), (RGen 4, genT 6)]) .-> (genT 1 .-> genT 3) .-> list (genT 1) .-> (list $ rec [(RGen 1 , list $ genT 2), (RGen 2, list $ genT 4), (RGen 3, list $ genT 5), (RGen 4, list $ genT 6)]))+ ,("groupBy5", Forall 7 5 $ [] :=> (genT 1 .-> rec [(RGen 1 ,genT 2), (RGen 2, genT 4), (RGen 3, genT 5), (RGen 4, genT 6), (RGen 5, genT 7)]) .-> (genT 1 .-> genT 3) .-> list (genT 1) .-> (list $ rec [(RGen 1 , list $ genT 2), (RGen 2, list $ genT 4), (RGen 3, list $ genT 5), (RGen 4, list $ genT 6), (RGen 5, list $ genT 7)]))+ ,("groupBy6", Forall 8 6 $ [] :=> (genT 1 .-> rec [(RGen 1 ,genT 2), (RGen 2, genT 4), (RGen 3, genT 5), (RGen 4, genT 6), (RGen 5, genT 7), (RGen 6, genT 8)]) .-> (genT 1 .-> genT 3) .-> list (genT 1) .-> (list $ rec [(RGen 1 , list $ genT 2), (RGen 2, list $ genT 4), (RGen 3, list $ genT 5), (RGen 4, list $ genT 6), (RGen 5, list $ genT 7), (RGen 6, list $ genT 8)]))+ ,("zip", Forall 2 0 $ [] :=> (list $ genT 1) .-> (list $ genT 2) .-> list (rec [(RLabel "1", genT 1),(RLabel "2", genT 2)]))+ ,("unzip", Forall 2 0 $ [] :=> (list $ rec [(RLabel "1", genT 1), (RLabel "2", genT 2)]) .-> rec [(RLabel "1", list $ genT 1), (RLabel "2", list $ genT 2)])+ ,("orderBy", Forall 2 0 $ [] :=> (genT 1 .-> genT 2) .-> (list $ genT 1) .-> (list $ genT 2))+ ,("orderByDescending", Forall 2 0 $ [] :=> (genT 1 .-> genT 2) .-> (list $ genT 1) .-> (list $ genT 2))+ ,("thenBy", Forall 2 0 $ [] :=> (genT 1 .-> genT 2) .-> (list $ genT 1) .-> (list $ genT 2))+ ,("thenByDescending", Forall 2 0 $ [] :=> (genT 1 .-> genT 2) .-> (list $ genT 1) .-> (list $ genT 2))+ ,("concatMap", Forall 2 0 $ [] :=> (genT 1 .-> (list $ genT 2)) .-> (list $ genT 1) .-> (list $ genT 2))+ -- ,("mapConst", Forall 2 0 $ [] :=> genT 1 .-> (list $ genT 2) .-> (list $ genT 1))+ ,("groupWith", Forall 3 0 $ [] :=> (genT 1 .-> genT 2) .-> (genT 1 .-> genT 3) .-> (list $ genT 1) .-> (list $ rec [(RLabel "1", genT 3), (RLabel "2", list $ genT 2)]))+ ,("const", Forall 2 0 $ [] :=> genT 1 .-> genT 2 .-> genT 1)+ -- ,("groupWithN", Forall 3 0 $ [] :=> (genT 1 .-> genT 2) .-> (genT 1 .-> genT 3) .-> (list $ genT 1) .-> (list $ rec [(RLabel "1", genT 3), (RLabel "2", list $ genT 2)]))+ ]
+ src/Database/Ferry/TypeSystem/Types.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE TypeSynonymInstances #-}+module Database.Ferry.TypeSystem.Types where++import Control.Monad.Reader+import Control.Monad.State+import Control.Monad.Error+import Control.Applicative hiding (Const(..))++import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.TypedCore.Data.Substitution +import Database.Ferry.Compiler.Error.Error+import Database.Ferry.TypedCore.Data.Instances()++import qualified Data.Map as M++type AlgW = ErrorT FerryError (ReaderT TyEnv (State (Int, Subst)))++runAlgW :: Substitutable a => TyEnv -> AlgW a -> (Either FerryError a, Subst)+runAlgW gam a = (x, s)+ where+ (x, (_, s)) = runState (runReaderT (runErrorT $ applyS a) gam) (1, (M.empty, M.empty))++getGamma :: AlgW TyEnv+getGamma = applyS ask++getSubst :: AlgW Subst+getSubst = liftM snd get++putSubst :: Subst -> AlgW ()+putSubst s = do+ (i, _) <- get+ put (i, s)++freshTyVar :: AlgW Ident +freshTyVar = do+ (n, theta) <- get+ put (n + 1, theta)+ return (show n)++lookupVariable :: Ident -> AlgW TyScheme+lookupVariable i = do + liftM (M.findWithDefault err i) getGamma+ where + err = error $ "Variable " ++ i ++ " not bound in env." ++addToEnv :: Ident -> TyScheme -> AlgW a -> AlgW a+addToEnv x t a = do+ _ <- getSubst+ gam <- getGamma+ local (\ _ -> M.insert x t gam) a++addSubstitution :: Subst -> FType -> FType -> Subst+addSubstitution (s, r) i t = let s' = M.singleton i t+ s'' = M.map (apply (s', M.empty)) s+ in (s' `M.union` s'', r)++updateSubstitution :: FType -> FType -> AlgW ()+updateSubstitution v t = do+ (i, s) <- get+ let s' = addSubstitution s v t+ put (i, s')++localAddSubstitution :: Substitutable a => FType -> FType -> AlgW a -> AlgW a+localAddSubstitution i t l = do+ s <- getSubst+ updateSubstitution i t+ v <- applyS l+ putSubst s+ return v++localAddRecSubstitution :: Substitutable a => RLabel -> RLabel -> AlgW a -> AlgW a+localAddRecSubstitution i t l = do+ s <- getSubst+ updateRecSubstitution i t+ v <- applyS l+ putSubst s+ return v++updateRecSubstitution :: RLabel -> RLabel -> AlgW ()+updateRecSubstitution v t = do+ (i, s) <- get+ let s' = addRecSubstitution s v t+ put (i, s')++addRecSubstitution :: Subst -> RLabel -> RLabel -> Subst+addRecSubstitution (s, r) i t = let r' = M.singleton i t+ r'' = M.map (apply (M.empty, r')) r+ in (s, r' `M.union` r'')++applyS :: Substitutable a => AlgW a -> AlgW a+applyS v = do+ s <- getSubst+ v' <- v+ return $ apply s v'+ +applySubst :: Substitutable a => a -> AlgW a+applySubst v = applyS $ pure v
+ src/Database/Ferry/TypeSystem/Unification.hs view
@@ -0,0 +1,109 @@+module Database.Ferry.TypeSystem.Unification where+ +import Database.Ferry.TypeSystem.Types+import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.Compiler.Error.Error+import Database.Ferry.TypedCore.Data.TypeFunction++import Control.Applicative hiding (Const(..))+import Control.Monad.Error++import qualified Data.List as L+import qualified Data.Set as S+++-- | Wrapper for type unification function+-- | it makes sure all substitutions are applied before actual unification is performed+unify :: FType -> FType -> AlgW ()+unify a b = do+ a' <- applyS $ pure a+ b' <- applyS $ pure b+ unify' (evalTy a') (evalTy b')++-- | Unification according to specification in documentation+-- | unify' is not a total function types star cannot be unified+-- | with anything.+unify' :: FType -> FType -> AlgW ()+unify' FUnit FUnit = pure ()+unify' FInt FInt = pure ()+unify' FFloat FFloat = pure ()+unify' FBool FBool = pure ()+unify' FString FString = pure ()+unify' (FList a) (FList b) = unify a b+unify' (FFn a1 b1) (FFn a2 b2) = unify a1 a2 >> unify b1 b2+unify' (FRec r1) (FRec r2) = unifyRecords r1 r2+unify' t v@(FVar a) = if v == t || S.notMember a (ftv t)+ then updateSubstitution v t+ else pure ()+unify' v@(FVar a) t = if v == t || S.notMember a (ftv t)+ then updateSubstitution v t+ else pure ()+unify' a1 a2 = throwError $ UnificationError a1 a2++-- | Helper functions for unifying records+unifyRecords :: [(RLabel, FType)] -> [(RLabel, FType)] -> AlgW ()+unifyRecords ((l1, t1):r1) ((l2, t2):r2) = do+ unifyFields l1 l2+ unify t1 t2+ unifyRecords r1 r2+unifyRecords [] [] = pure ()+unifyRecords r1 r2 = throwError $ UnificationRecError r1 r2 ++-- | Helper function for unifyin individual record fields+unifyFields :: RLabel -> RLabel -> AlgW ()+unifyFields r1@(RLabel l1) r2@(RLabel l2) = if l1 == l2 then return () else throwError $ UnificationOfRecordFieldsFailed r1 r2+unifyFields r1@(RVar i) r2 = if r1 == r2 || S.notMember i (frv r2)+ then updateRecSubstitution r1 r2+ else pure ()+unifyFields r1 r2@(RVar i) = if r1 == r2 || S.notMember i (frv r1)+ then updateRecSubstitution r2 r1+ else pure ()+unifyFields r1 r2 = throwError $ UnificationFail r1 r2++-- | Function for helping with predicate merging+mergeQuals :: [Pred] -> [Pred] -> AlgW [Pred]+mergeQuals t1 t2 = consistents $ mergeQualsW t1 t2+ where+ mergeQualsW [] t = pure t+ mergeQualsW t [] = pure t+ mergeQualsW (p:ps) t = if L.elem p t then mergeQualsW ps t else mergeQualsW ps (p:t)++-- | Add a predicate to a list of predicates+insertQual :: Pred -> [Pred] -> AlgW [Pred]+insertQual p@(IsIn _ _) ps = pure (p:ps)+insertQual p@(Has v f t) (p2@(Has v2 f2 t2):ps) | v == v2 && f == f2 = do+ unify t t2+ t' <- applySubst t+ pure ((Has v f t'):ps)+ | otherwise = do+ ps' <- insertQual p ps+ pure (p2:ps')+insertQual p (p':ps) = do+ ps' <- insertQual p ps+ pure (p':ps')+insertQual p [] = pure [p]++mergeQuals' :: [[Pred]] -> AlgW [Pred]+mergeQuals' pss = foldr (\p r -> do+ r' <- r+ mergeQuals p r') (pure []) pss++-- | Check concistency of set of predicates +consistents :: AlgW [Pred] -> AlgW [Pred]+consistents pss = do + ps <- pss+ case ps of+ (p:ps') -> do+ p' <- consistent p+ applySubst ps'+ ps'' <- consistents $ pure ps'+ applySubst (p':ps'')+ [] -> pure []++consistent :: Pred -> AlgW Pred+consistent p@(Has (FRec els) f t) = case (L.lookup f els) of+ Just a -> do+ unify a t+ applySubst p+ Nothing -> pure p+consistent p = pure p
+ src/Database/Ferry/TypedCore/Boxing/Boxing.hs view
@@ -0,0 +1,243 @@+{-| This module performs boxing on a typed AST.+This is an essential step in the compilation pipeline.+It is described in more detail in:+http://www-db.informatik.uni-tuebingen.de/files/publications/avalanche-safe-linq.pdf+Figure 7 rule 17 and 18+-}+module Database.Ferry.TypedCore.Boxing.Boxing where++import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Data.Instances()+import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.Common.Data.Base++import Control.Monad.Reader+ +import qualified Data.Map as M (lookup)+import Data.Maybe (fromJust)++-- | Execute the unboxing in the presence of type environment env+runBoxing :: TyEnv -> CoreExpr -> CoreExpr+runBoxing env = fst . flip runReader (env, Nothing, emptyEnv) . topBox++-- | An expression can be either a list or an atom.+-- a unboxed list is atom. An boxed atom becomes a list.+data Box = Atom+ | List+ | BFn Box Box+ deriving (Eq, Show)++-- | Box environment +type BoxEnv = [(Identifier, Box)]++-- | Expected boxing value+type Context = Maybe Box++-- | Initial box environment+emptyEnv :: BoxEnv+emptyEnv = [] ++-- | Boxing environment, containing type environment, context and boxing environment+type Boxing = Reader (TyEnv, Context, BoxEnv)++-- * Helper function that modify the state++-- | Store identifier i with boxing value b in the boxing environment for+-- the given boxing computation+addToEnv :: Identifier -> Box -> Boxing a -> Boxing a+addToEnv i b = local (\(gE, cE, bE) -> (gE, cE, (i, b):bE))++-- | Lookup the type scheme of an identifier in the type environment+fromGam :: Identifier -> Boxing (Maybe TyScheme)+fromGam i = do+ (g, _, _) <- ask+ return $ M.lookup i g++-- | Lookup the boxing value of an identifier in the box environment +fromEnv :: Identifier -> Boxing Box+fromEnv i = do+ (_, _, env) <- ask+ case lookup i env of+ Just x -> return x+ Nothing -> error $ "Identifier: " ++ i ++ " not found in env during boxing."++-- | Run the boxing computation with expected boxing value t+withContext :: Box -> Boxing a -> Boxing a+withContext t = local (\(gE, _, bE) -> (gE, Just t, bE)) ++-- | Get the boxing context value (or expected boxing value)+getFromContext :: Boxing (Maybe Box) +getFromContext = do+ (_, c, _) <- ask+ return c++-- | Run the boxing computation without an expected boxing value +noContext :: Boxing a -> Boxing a+noContext = local (\(gE, _, bE) -> (gE, Nothing, bE))++-- | Convert a type into a boxing value +trans :: FType -> Box+trans (FList _) = List+trans (FFn t1 t2) = BFn (trans t1) (trans t2)+trans _ = Atom+ +{-|+Heavily simplified inst, it doesn't work as a proper inst+ from the type system it only works for types that are passed to trans.+-}+inst :: TyScheme -> FType+inst (Forall _ _ (_ :=> t)) = t++{-| +Determine how to transform an expression given an expected box value+and the box value of the expression. +-}+boxOp :: Box -> Box -> CoreExpr -> CoreExpr+boxOp Atom List = unboxFn+boxOp List Atom = boxFn+boxOp _ _ = id++{-| Wrap the given expression in a box-function call -}+boxFn :: CoreExpr -> CoreExpr+boxFn e = App t (Var t' "box") $ ParExpr t e+ where + t@(q :=> ty) = typeOf e+ t' = q :=> ty .-> ty++{-| Wrap the given expression in an unbox-function call -}+unboxFn :: CoreExpr -> CoreExpr+unboxFn e = App t (Var t' "unBox") $ ParExpr t e+ where + t@(q :=> ty) = typeOf e+ t' = q :=> ty .-> ty ++{-| Check whether the expected box value (if specified) matches the inferred box value-}+resultCheck :: (CoreExpr, Box) -> Boxing (CoreExpr, Box)+resultCheck (e, psi) = do+ psir <- getFromContext + case (psir, psi) of+ (Just p, psi') | p == psi' -> return (e, psi') + | otherwise -> error $ "Expected box sort doesn't match inferred sort in expression: " ++ show e+ (Nothing, psi') -> return (e, psi')++-- * The actual boxing process+++-- | Deal with corner case of lazy unboxing, the result +-- type is a list but the boxing says it's an atom+-- in that case we perform the unboxing+topBox :: CoreExpr -> Boxing (CoreExpr, Box)+topBox e = do + (e', psi) <- box e+ let t = typeOf e'+ case t of+ (_ :=> (FList _)) -> return (boxOp psi List e', List)+ _ -> return (e', psi)++-- | Run the boxing transformation over an expression, computing+-- for every epression a new expression and its box value+box :: CoreExpr -> Boxing (CoreExpr, Box)+-- A constant is simply an atom+box c@(Constant _ _) = resultCheck (c, Atom)+-- Nil is an empty list and thus box value list+box n@(Nil _) = resultCheck (n, List)+-- Const adds an element (an atom, a nested list has to be unboxed!) to another list+-- There are no expectations on the box value of its children.+box (Cons t e1 e2) = do+ (e1', psi) <- noContext $ box e1+ (e2', psi2) <- noContext $ box e2 + resultCheck (Cons t (boxOp psi Atom e1') (boxOp psi2 List e2'), List)+-- Element from a list is an atom (even it is a list, it is still unboxed)+box (Elem t e s) = do+ (e', psi) <- noContext $ box e+ resultCheck (Elem t (boxOp psi Atom e') s, Atom)+-- A table is a list of tuples and thus has box value list+box t@(Table _ _ _ _) = resultCheck (t, List)+-- There are no expectations on the context of the conditional,+-- the branches however have to meet the expectations of the entire+-- if then else construction+box (If t e1 e2 e3) = do+ (e1', psi1) <- noContext $ box e1+ (e2', psi2) <- box e2+ (e3', psi3) <- box e3+ if psi2 == psi3+ then resultCheck (If t (boxOp psi1 Atom e1') e2' e3', psi3)+ else resultCheck (If t (boxOp psi1 Atom e1') (boxOp psi2 Atom e2') (boxOp psi3 Atom e3'), Atom) +-- The bound expression doesn't have a context, the context of the whole let is equal to the context of e2+box (Let t s e1 e2) = do+ (e1', psi1) <- noContext $ box e1+ (e2', psi2) <- addToEnv s psi1 $ box e2+ resultCheck (Let t s e1' e2', psi2)+-- A variable has a type in the environment if it is a global variable+-- it's box value can be retrieved from its type.+-- Otherwise the variable has to have a box value in the box environment+box (Var t x) = do + ty <- fromGam x+ case ty of+ Nothing -> do+ psi <- fromEnv x+ resultCheck (Var t x, psi)+ (Just t') -> do+ let psi = trans $ inst t' + resultCheck (Var t x, psi)+-- A record is an atom +box (Rec t els) = do + els' <- mapM (noContext . boxRec) els+ return (Rec t els', Atom)+-- Function application+-- There are no expectations about the box value of e1+-- It will however give a box value from box value to box value.+-- The expected box value of the argument is equal to the box value+-- at the argument position of the box function type.+-- The result of the application is equal to the box value of result box value+-- in the inferred box function type.+box (App t e1 e2) = do+ (e1', psi) <- noContext $ box e1+ let (psia, psir ) = case psi of+ (BFn psia' psir') -> (psia', psir')+ _ -> error $ show psi ++ "not a function box" + (e2', _psi2) <- withContext psia $ boxParam e2+ resultCheck (App t e1' e2', psir)+-- Similar to app+box (BinOp t (Op o) e1 e2) = do+ ty <- fromGam o+ case ty of+ Nothing -> error $ "Non primitive operator during boxing phase, this should not happen: " ++ show o+ (Just t') -> do+ let (BFn psi1 (BFn psi2 psi3)) = trans $ inst t'+ (e1', psi1') <- noContext $ box e1+ (e2', psi2') <- noContext $ box e2+ resultCheck (BinOp t (Op o) (boxOp psi1' psi1 e1') (boxOp psi2' psi2 e2'), psi3)++-- Box the expression in a record element+-- They should be of box type atom, a list needs to be unboxed.+boxRec :: RecElem -> Boxing RecElem +boxRec (RecElem t x e) = do+ (e', psi) <- box e+ return $ RecElem t x (boxOp psi Atom e') ++-- | Box function parameters+boxParam :: Param -> Boxing (Param, Box) +boxParam (ParExpr t e) = do+ (e', psi) <- noContext $ box e+ psie <- getFromContext+ return $ (ParExpr t $ boxOp psi (fromJust psie) e', fromJust psie)+boxParam (ParAbstr t p e) = do+ let args = p+ psie <- getFromContext+ let (asso, boxR) = varsWithBox args $ fromJust psie+ (e', psi) <- foldr (\(v, t') r -> addToEnv v t' r) (noContext $ box e) asso+ return (ParAbstr t p (boxOp psi boxR e'), boxR)+ +{-+-- | Retrieve the variables in a pattern +getVars :: Pattern -> [String]+getVars (PVar v) = [v]+getVars (Pattern p) = p +-}++-- | Construct a list of all function arguments with their respective box value, and the result box value of the function.+varsWithBox :: [String] -> Box -> ([(String, Box)], Box)+varsWithBox [] b = ([], b)+varsWithBox (x:xs) (BFn b1 b2) = (\(l, b) -> ((x, b1):l, b)) (varsWithBox xs b2)+varsWithBox _ _ = error $ "varswithBox err, should not happen"
+ src/Database/Ferry/TypedCore/Convert/CoreToAlgebra.hs view
@@ -0,0 +1,960 @@+{-# LANGUAGE TemplateHaskell #-}+{- |+This module transforms typed ferry core into a relational algebra DAG.+The transformation assumes that given programs are type correct and some+functions on lists have been inlined (transformations performed by RewriteStage).++For a more complete overview see:++http://www-db.informatik.uni-tuebingen.de/files/publications/avalanche-safe-linq.pdf+-}+module Database.Ferry.TypedCore.Convert.CoreToAlgebra where+++import Database.Ferry.Impossible+import Database.Ferry.Common.Data.Base++import Database.Ferry.Algebra++import Database.Ferry.TypedCore.Data.Type (Qual (..), FType (..), RLabel (..), isPrim)+import Database.Ferry.TypedCore.Data.TypedCore as T++import qualified Data.Map as M +import qualified Data.List as L+import Data.Maybe (fromJust, isJust)++-- | Section introducing aliases for commonly used columns++-- | Results are stored in column:+resCol, resColPrime, resColPrimePrime, ordCol, ordPrime, iterPrime, iterR, posPrime, posPrimePrime, outer, inner, oldCol :: String+resCol = "item99999001"+resColPrime = "item99999002"+resColPrimePrime = "item99999003"+ordCol = "item99999801"+ordPrime = "item99999804"+iterPrime = "item99999701"+iterR = "item99999703"+posPrime = "item99999601"+posPrimePrime = "item99999602"+outer = "item99999501"+inner = "item99999401"+oldCol = "item99999301"++-- | Construct the ith item columns+mkPrefixCol :: Int -> String+mkPrefixCol i = "item" ++ prefixCol ++ (show i)++-- | Construct the ith iter column+mkPrefixIter :: Int -> String+mkPrefixIter i = "iter" ++ prefixCol ++ (show i)++-- | Prefix for intermediate column numbers+prefixCol :: String+prefixCol = "9999"++-- | Transform Ferry core into a relation algebra modelled as a DAG+coreToAlgebra :: CoreExpr -> GraphM AlgRes+-- | Primitive values+coreToAlgebra (Constant _ CUnit) = do+ n1 <- attach "pos" natT (nat 1) + =<< attach "item1" intT (int 0) + =<< getLoop+ return (n1, [Col 1 AInt], emptyPlan)+coreToAlgebra (Constant _ (CInt i)) = do + n1 <- attach "pos" natT (nat 1) + =<< attach "item1" intT (int i) + =<< getLoop+ return (n1, [Col 1 AInt], emptyPlan)+coreToAlgebra (Constant _ (CBool i)) = do+ n1 <- attach "pos" natT (nat 1) + =<< attach "item1" boolT (bool i) + =<< getLoop+ return (n1, [Col 1 ABool], emptyPlan)+coreToAlgebra (Constant _ (CFloat i)) = do+ n1 <- attach "pos" natT (nat 1) + =<< attach "item1" doubleT (double i) + =<< getLoop+ return (n1, [Col 1 ADouble], emptyPlan)+coreToAlgebra (Constant _ (CString i)) = do+ n1 <- attach "pos" natT (nat 1) + =<< attach "item1" stringT (string i) + =<< getLoop+ return (n1, [Col 1 AStr], emptyPlan)+-- Binary operators+coreToAlgebra (BinOp (_ :=> t) (Op o) e1 e2) = do+ (q1, [Col 1 _t1], _m1) <- coreToAlgebra e1+ (q2, [Col 1 _t2], _m2) <- coreToAlgebra e2+ n1 <- proj [("iter", "iter"), ("pos", "pos"), ("item1", resCol)] + =<< oper o resCol "item1" (mkPrefixCol 1) + =<< eqJoin "iter" (mkPrefixIter 1) q1 + =<< proj [(mkPrefixIter 1, "iter"), (mkPrefixCol 1, "item1")] q2+ return (n1, fst $ typeToCols t 1, emptyPlan)+-- Let bindings+coreToAlgebra (Let _ s e1 e2) = do+ (q1, cs1, m1) <- coreToAlgebra e1+ withBinding s (q1, cs1, m1) $ coreToAlgebra e2+-- Variable lookup+coreToAlgebra (Var _ n) = fromGam n+-- Record construction, body of the rule can be found in recElemsToAlgebra+coreToAlgebra (Rec _ (e:els)) = foldl recElemsToAlgebra (recElemToAlgebra e) els+coreToAlgebra (Rec _ []) = $impossible+-- Record element access.+coreToAlgebra (Elem _ e n) = do+ (q1, cs1 ,(SubPlan ts1)) <- coreToAlgebra e+ let csn = getCol n cs1+ let (csn', i) = decrCols csn+ let ln = leafNumbers csn'+ let ts = SubPlan $ M.fromList [ (l, fromJust r) | l <- ln, let r = M.lookup (l+i) ts1, isJust r]+ let projPairs = zip (leafNames csn') (leafNames csn)+ n1 <- proj (("iter", "iter"):("pos", "pos"):projPairs) q1+ return (n1, csn', ts)+--Empty lists+coreToAlgebra (Nil (_ :=> (FList t))) = do+ let cs = fst $ typeToCols t 1+ let schema = ("iter", natT):("pos", natT):(colsToSchema cs)+ n1 <- emptyTable schema+ sub <- case t of+ (FList _) -> do+ s <- coreToAlgebra $ Nil $ [] :=> t+ return $ SubPlan $ M.singleton 1 s+ _ -> return emptyPlan+ return (n1, cs, sub)+coreToAlgebra (Nil _) = $impossible -- After type checking the only thing that reaches this stage has a list type+-- List constructor, because of optimisation chances contents has been directed to special functions+coreToAlgebra (c@(Cons _ _ _)) = listFirst c+-- Database tables+coreToAlgebra (Table _ n cs ks) = do+ let cs' = coreCol2AlgCol cs+ let keys' = key2Key cs' ks+ loop <- getLoop+ n1 <- cross loop + =<< rank "pos" (map (\ki -> (ki, Asc)) $ head keys') + =<< dbTable n cs' keys'+ return (n1, cs', emptyPlan)+-- If then else+coreToAlgebra (If _ e1 e2 e3) = do+ (q1, _cs1, _ts1) <- coreToAlgebra e1+ -- Get current gamma+ gam <- getGamma+ -- Build loop and gamma for then branch + loopThen <- proj [("iter", "iter")] =<< select "item1" q1+ gamThen <- transformGam algResLoop loopThen gam + --Evaluate then branch+ (q2, cs2, ts2) <- withContext gamThen loopThen $ coreToAlgebra e2+ -- Build loop and gamma for else branch+ loopElse <- proj [("iter", "iter")] + =<< select resCol + =<< notC resCol "item1" q1+ gamElse <- transformGam algResLoop loopElse gam + --Evaluate else branch+ (q3, _cs3, ts3) <- withContext gamElse loopElse $ coreToAlgebra e3+ --Construct result+ let ks = keys ts2+ let cols = leafNames cs2+ let colsDiff = cols L.\\ ks+ n1 <- attach ordCol natT (nat 1) q2+ q' <- rownum iterPrime ["iter", ordCol, "pos"] Nothing+ =<< union n1 + =<< attach ordCol natT (nat 2) q3+ let projPairs = zip colsDiff colsDiff ++ zip ks (repeat iterPrime)+ n2 <- proj (("iter","iter"):("pos","pos"):projPairs) q'+ ts <- mergeTableStructure q' ts2 ts3+ return (n2, cs2, ts)+-- Compile function application, as we do not have functions as results the given+-- argument can be evaluated and then be passed to the compileApp function.+coreToAlgebra (App _ e1 e2) = compileAppE1 e1 =<< compileParam e2+ ++-- | Transform the variable environment +transformGam :: (AlgNode -> (String, AlgRes) -> GraphM (String, AlgRes)) + -> AlgNode -> Gam -> GraphM Gam+transformGam f loop gamma = mapM (f loop) gamma++-- | Transformation of gamma for if then else +algResLoop :: AlgNode -> (String, AlgRes) -> GraphM (String, AlgRes)+algResLoop loop (n, (i, cs, pl)) = do+ i' <- eqJoin "iter" "iter" i loop+ return (n, (i', cs, pl))++-- | Compile a function parameter+-- | Function is partial, i.e. it doesn't compile lambda's as arguments +compileParam :: Param -> GraphM AlgRes+compileParam (ParExpr _ e1) = coreToAlgebra e1+compileParam (ParAbstr _ _ _) = $impossible++-- | Compile function application.+-- | Expects a core expression the function, and the evaluated argument+compileAppE1 :: CoreExpr -> AlgRes -> GraphM AlgRes+compileAppE1 (App _ (Var _ "zip") (ParExpr _ e1)) (q2', cs2, (SubPlan ts2)) =+ do+ (q1', cs1, (SubPlan ts1)) <- coreToAlgebra e1+ q1 <- absPos q1' cs1+ q2 <- absPos q2' cs2+ let offSet = colSize cs1+ let cs2' = incrCols offSet cs2+ let projPairs1 = zip (leafNames cs1) (leafNames cs1)+ let projPairs2 = zip (leafNames cs2') (leafNames cs2')+ let projPairs2' = zip (leafNames cs2') (leafNames cs2) + q <- eqTJoin [("iter", iterPrime), ("pos", posPrime)] (("iter", "iter"):("pos", "pos"):(projPairs1 ++ projPairs2)) q1+ =<< proj ((iterPrime, "iter"):(posPrime, "pos"):projPairs2') q2+ let cs = [NCol "1" cs1, NCol "2" cs2']+ let ts = SubPlan $ M.union ts1 $ M.mapKeysMonotonic (+ offSet) ts2+ return (q, cs, ts)+compileAppE1 (Var _ "unzip") (q, [NCol "1" cs1, NCol "2" cs2], (SubPlan ts)) =+ do+ let (cs2d, d) = decrCols cs2+ let projPairs1 = zip (leafNames cs1) (leafNames cs1)+ let projPairs2 = zip (leafNames cs2d) (leafNames cs2)+ q' <- proj [("iter", "iter"),("pos", "pos"), ("item1", "iter"), ("item2", "iter")]+ =<< attach "pos" natT (nat 1) =<< getLoop+ q1 <- proj (("iter", "iter"):("pos", "pos"):projPairs1) q+ q2 <- proj (("iter", "iter"):("pos", "pos"):projPairs2) q+ let cs = [NCol "1" [Col 1 surT], NCol "2" [Col 2 surT]]+ let ln1 = leafNumbers cs1+ let ln2 = leafNumbers cs2d+ let ts1 = SubPlan $ M.fromList [(l, ts M.! l) | l <- ln1, isJust $ M.lookup l ts]+ let ts2 = SubPlan $ M.fromList [(l, ts M.! (l + d)) | l <- ln2, isJust $ M.lookup (l +d) ts]+ let ts' = SubPlan $ M.fromList [(1, (q1, cs1, ts1)),(2, (q2, cs2d,ts2))]+ return (q', cs, ts')+ +compileAppE1 (App _ (Var _ "map") l@(ParAbstr _ _ _)) (q1, cs1, ts1) = + do+ gam <- getGamma+ (_qv', qv, mapv, loopv, gamV) <- mapForward gam q1 cs1+ (q2, cs2, ts2) <- withContext gamV loopv $ compileLambda [(qv, cs1, ts1)] l+ let csProj2 = zip (leafNames cs2) (leafNames cs2)+ q <- proj (("iter",outer):("pos", posPrime):csProj2)+ =<< eqJoin "iter" inner q2 mapv+ return (q, cs2, ts2)+compileAppE1 (App _ (Var _ "takeWhile") l@(ParAbstr _ _ _)) (q1, cs1, ts1) =+ do+ gam <- getGamma+ loop <- getLoop+ (qv', qv, _mapv, loopv, gamV) <- mapForward gam q1 cs1+ (q2, _cs2, _ts2) <- withContext gamV loopv $ compileLambda [(qv, cs1, ts1)] l+ let projPairs = zip (leafNames cs1) (leafNames cs1)+ q' <- proj (("iter","iter"):("pos", "pos"):(resCol, resCol):projPairs)+ =<< eqJoin inner iterPrime qv'+ =<< proj [(iterPrime, "iter"),(resCol, "item1")] q2+ qM <- aggr [(Min, posPrime, Just "pos")] (Just "iter")+ =<< select posPrime + =<< notC posPrime resCol q'+ qE <- proj (("iter", "iter"):("pos", "pos"):projPairs)+ =<< eqJoin "iter" iterPrime q1+ =<< proj [(iterPrime, "iter")] + =<< difference loop + =<< proj [("iter", "iter")] qM+ q'' <- union qE+ =<< proj (("iter", "iter"):("pos", "pos"):projPairs)+ =<< select resColPrime+ =<< oper ">" resColPrime posPrime "pos"+ =<< eqJoin "iter" iterPrime q'+ =<< proj [(iterPrime, "iter"), (posPrime, posPrime)] qM+ return (q'', cs1, ts1)+compileAppE1 (App _ (App _ (Var _ "zipWith") l@(ParAbstr _ _ _)) (ParExpr _ e1)) (q2, cs2, ts2) =+ do+ gam <- getGamma+ (q1, cs1, ts1) <- coreToAlgebra e1+ q1' <- absPos q1 cs1+ q2' <- absPos q2 cs2+ let offSet = colSize cs1+ let cs2' = incrCols offSet cs2+ q <- eqTJoin [("pos", posPrime), ("iter", iterPrime)] (("iter", "iter"):("pos", "pos"): ((zip (leafNames cs1) (leafNames cs1)) ++ (zip (leafNames cs2') (leafNames cs2')))) q1'+ =<< proj ((iterPrime, "iter"):(posPrime, "pos"):(zip (leafNames cs2') (leafNames cs2))) q2'+ (_qv', qv, mapv, loopv, gamV) <- mapForward gam q $ cs1 ++ cs2'+ qv1 <- proj (("iter", "iter"):("pos", "pos"):(zip (leafNames cs1) (leafNames cs1))) qv+ qv2 <- proj (("iter", "iter"):("pos", "pos"):(zip (leafNames cs2) (leafNames cs2'))) qv+ (q3, cs3, ts3) <- withContext gamV loopv $ compileLambda [(qv1, cs1, ts1), (qv2, cs2, ts2)] l+ qr <- proj (("iter", outer):("pos", posPrime):(zip (leafNames cs3) (leafNames cs3))) + =<< eqJoin "iter" inner q3 mapv+ return (qr, cs3, ts3)+compileAppE1 (App _ (Var _ "dropWhile") l@(ParAbstr _ _ _)) (q1, cs1, ts1) =+ do+ gam <- getGamma+ (qv', qv, _mapv, loopv, gamV) <- mapForward gam q1 cs1+ (q2, _cs2, _ts2) <- withContext gamV loopv $ compileLambda [(qv, cs1, ts1)] l+ let projPairs = zip (leafNames cs1) (leafNames cs1)+ q' <- proj (("iter","iter"):("pos", "pos"):(resCol, resCol):projPairs)+ =<< eqJoin inner iterPrime qv'+ =<< proj [(iterPrime, "iter"),(resCol, "item1")] q2+ q'' <- proj (("iter", "iter"):("pos", "pos"):projPairs)+ =<< select ordCol+ =<< oper "||" ordCol resColPrimePrime resColPrime+ =<< oper "==" resColPrimePrime "pos" posPrime+ =<< oper ">" resColPrime "pos" posPrime + =<< eqJoin "iter" iterPrime q'+ =<< proj [(iterPrime, "iter"), (posPrime, posPrime)]+ =<< aggr [(Min, posPrime, Just "pos")] (Just "iter")+ =<< select posPrime + =<< notC posPrime resCol q'+ return (q'', cs1, ts1)+compileAppE1 (App _ (Var _ "sortWith") l@(ParAbstr _ _ _)) (q1, cs1, ts1) =+ do+ gam <- getGamma+ (_qv', qv, mapv, loopv, gamV) <- mapForward gam q1 cs1+ (q2, cs2, _ts2) <- withContext gamV loopv $ compileLambda [(qv, cs1, ts1)] l+ let projPairs = zip (leafNames cs1) (leafNames cs1)+ q <- proj (("iter", outer):("pos", resCol):projPairs) =<< select resColPrime+ =<< oper "==" resColPrime "pos" posPrime + =<< eqJoin "iter" outer q1 + =<< proj [(inner, inner), (outer, outer), (posPrime, posPrime), (resCol, resCol)] + =<< rownum resCol (leafNames cs2) (Just outer) + =<< eqJoin "iter" inner q2 mapv+ return (q, cs1, ts1)+compileAppE1 (App _ (Var _ "max") (ParExpr _ e1)) (q2, [Col 1 t], _ts2) = + do+ (q1, [Col 1 _], _ts1) <- coreToAlgebra e1+ q <- attach "pos" natT (nat 1) + =<< proj [("iter", "iter"),("item1", resCol)] + =<< aggr [(Max, resCol, Just "item1")] (Just "iter") + =<< union q1 q2+ return (q, [Col 1 t], emptyPlan)+compileAppE1 (App _ (Var _ "min") (ParExpr _ e1)) (q2, [Col 1 t], _ts2) =+ do+ (q1, [Col 1 _], _ts1) <- coreToAlgebra e1+ q <- attach "pos" natT (nat 1) + =<< proj [("iter", "iter"),("item1", resCol)] + =<< aggr [(Min, resCol, Just "item1")] (Just "iter") + =<< union q1 q2+ return (q, [Col 1 t], emptyPlan)+compileAppE1 (App _ (Var _ "filter") l@(ParAbstr _ _ _)) (q1, cs1, ts1) =+ do+ gam <- getGamma+ (qv', qv, _mapv, loopv, gamV) <- mapForward gam q1 cs1+ (q2, _cs2, _ts2) <- withContext gamV loopv $ compileLambda [(qv, cs1, ts1)] l+ let csProj = zip (leafNames cs1) (leafNames cs1)+ q <- proj (("iter", "iter"):("pos", "pos"):csProj)+ =<< select resCol + =<< eqJoin inner iterPrime qv' + =<< proj [(iterPrime, "iter"), (resCol, "item1")] q2+ return (q, cs1, ts1)+compileAppE1 (Var _ "head") (q1', cs1, ts1) =+ do+ q1 <- absPos q1' cs1+ q <- posSelect 1 [("pos", Asc)] (Just "iter") q1+ return (q, cs1, ts1)+compileAppE1 (Var _ "tail") (q1', cs1, ts1) =+ do+ let projPairs = zip (leafNames cs1) (leafNames cs1)+ q1 <- absPos q1' cs1+ q <- proj (("iter", "iter"):("pos", "pos"):projPairs)+ =<< select resCol + =<< oper ">" resCol "pos" oldCol + =<< attach oldCol natT (nat 1) q1+ return (q, cs1, ts1)+compileAppE1 (Var _ "concat") (q, _cs, SubPlan ts) =+ do+ let [(1, (qs, css, tss))] = M.toList ts+ let projPairs = zip (leafNames css) (leafNames css)+ q' <- proj (("iter", iterPrime):("pos", posPrimePrime):projPairs)+ =<< rank posPrimePrime [(posPrime, Asc), ("pos", Asc)]+ =<< eqJoin "iter" resCol qs+ =<< proj [(iterPrime, "iter"),(posPrime, "pos"), (resCol, "item1")] q+ return (q', css, tss) +compileAppE1 (Var _ "nub") (q, cs, ts) =+ do+ let projPairs = ("iter", "iter"):("pos", "pos"):(zip (leafNames cs) (leafNames cs))+ q' <- proj projPairs+ =<< aggr ((Min, "pos", Just "pos"):(Dist, "iter", Just "iter"):[(Dist, c, Just c) | c <- leafNames cs]) (Just resCol)+ =<< rowrank resCol (map (\x -> (x, Asc)) ("iter":(leafNames cs))) q+ return (q', cs, ts)+compileAppE1 (Var mt "count") (q, cs, ts) = compileAppE1 (Var mt "length") (q, cs, ts)+compileAppE1 (App _ (Var _ "index") (ParExpr _ e1)) (q2, _cs2, _ts2) =+ do+ (q1, cs1, ts1) <- coreToAlgebra e1+ is <- proj [(iterPrime, "iter"), (resCol, resColPrimePrime)] + =<< oper "+" resColPrimePrime resColPrime resCol+ =<< attach resColPrime natT (nat 1)+ =<< cast "item1" resCol natT q2+ let projPairs = zip (leafNames cs1) (leafNames cs1) + q <- proj (("iter", "iter"):("pos", "pos"):projPairs)+ =<< select resColPrime + =<< oper "==" resColPrime resCol "pos"+ =<< eqJoin iterPrime "iter" is q1+ return (q, cs1, ts1)+compileAppE1 (App _ (Var _ "mapConst") (ParExpr _ e1)) (q2, _cs2, _ts2) =+ do+ (q1, cs1, ts1) <- coreToAlgebra e1+ let projPairs = zip (leafNames cs1) (leafNames cs1)+ q1' <- proj ((iterPrime, "iter") : projPairs) q1+ q <- proj (("iter", "iter"):("pos", "pos"):projPairs)+ =<< eqJoin iterPrime "iter" q1' + =<< proj [("iter", "iter"),("pos", "pos")] q2+ return (q, cs1, ts1)+compileAppE1 (Var _ "reverse") (q1, cs1, ts1) =+ do+ let projPairs = zip (leafNames cs1) (leafNames cs1)+ q <- proj (("iter", "iter"):("pos", posPrime):projPairs)+ =<< rownum' posPrime [("pos", Desc)] (Just "iter") q1+ return (q, cs1, ts1)+compileAppE1 (Var _ "length") (q, _cs, _ts) = + do+ loop <- getLoop+ q''' <- aggr [(Count, "item1", Nothing)] (Just "iter") q+ q'' <- attach "item1" intT (int 0)+ =<< difference loop + =<< proj [("iter", "iter")] q'''+ q' <- attach "pos" natT (nat 1)+ =<< union q'' q''' + return (q', [Col 1 AInt], emptyPlan)+ +compileAppE1 (Var _ "box") (q, cs, ts) =+ do+ q' <- attach "pos" natT (nat 1) + =<< proj [("iter", "iter"),("item1", "iter")] + =<< getLoop+ return (q', [Col 1 surT], subPlan 1 (q, cs, ts))+compileAppE1 (Var mt@(_ :=> FFn _ t) "the") (q, cs, ts) = + if (isPrim t) + then+ do + let projPairs = (:) ("iter", "iter") $ zip (leafNames cs) (leafNames cs)+ q' <- attach "pos" natT (nat 1) =<< distinct =<< proj projPairs q+ return (q', cs, ts) + else + compileAppE1 (Var mt "head") (q, cs, ts)+compileAppE1 (Var mt "all") (q, cs, ts) = compileAppE1 (Var mt "and") (q, cs, ts)+compileAppE1 (Var _ "and") (q, cs, ts) =+ do+ q' <- attach "pos" natT (nat 1)+ =<< proj [("iter", "iter"), ("item1", resCol)]+ =<< aggr [(Min, resCol, Just "item1")] (Just "iter")+ =<< union q+ =<< attach "pos" natT (nat 1) =<< attach "item1" boolT (bool True) =<< getLoop + return (q', cs, ts)+compileAppE1 (Var (_ :=> FFn _ t) "sum") (q, cs, _) =+ do+ let ty = case t of+ FInt -> intT+ FFloat -> doubleT+ (FVar _) -> intT+ _ -> $impossible+ loop <- getLoop+ q' <- aggr [(Sum, "item1", Just "item1")] (Just "iter") q+ q'' <- attach "item1" ty (int 0)+ =<< difference loop + =<< proj [("iter", "iter")] q'+ q''' <- attach "pos" natT (nat 1) + =<< union q'' q'+ return (q''', cs, emptyPlan)+compileAppE1 (Var _ "maximum") (q, cs, _) =+ do+ q' <- attach "pos" natT (nat 1)+ =<< proj [("iter", "iter"), ("item1", resCol)]+ =<< aggr [(Max, resCol, Just "item1")] (Just "iter") q+ return (q', cs, emptyPlan)+compileAppE1 (Var _ "minimum") (q, cs, _) =+ do+ q' <- attach "pos" natT (nat 1)+ =<< proj [("iter", "iter"), ("item1", resCol)]+ =<< aggr [(Min, resCol, Just "item1")] (Just "iter") q+ return (q', cs, emptyPlan)+compileAppE1 (Var (_ :=> FFn _ t) "product") (q, cs, _) =+ do+ let ty = case t of+ FInt -> intT+ FFloat -> doubleT+ (FVar _) -> intT+ _ -> $impossible+ loop <- getLoop+ q' <- aggr [(Prod, "item1", Just "item1")] (Just "iter") q+ q'' <- attach "item1" ty (int 1)+ =<< difference loop + =<< proj [("iter", "iter")] q'+ q''' <- attach "pos" natT (nat 1) + =<< union q'' q'+ return (q''', cs, emptyPlan)+compileAppE1 (Var _ "or") (q, cs, ts) =+ do+ q' <- attach "pos" natT (nat 1)+ =<< proj [("iter", "iter"), ("item1", resCol)]+ =<< aggr [(Max, resCol, Just "item1")] (Just "iter") + =<< union q+ =<< attach "pos" natT (nat 1) =<< attach "item1" boolT (bool False) =<< getLoop+ return (q', cs, ts)+compileAppE1 (Var _ "not") (q, [Col 1 t], _ts) =+ do+ q' <- proj [("iter", "iter"), ("pos", "pos"), ("item1", resCol)]+ =<< notC resCol "item1" q+ return (q', [Col 1 t], emptyPlan)+compileAppE1 (Var _ "integerToDouble") (q, _cs, _ts) =+ do+ q' <- proj [("iter", "iter"), ("pos", "pos"), ("item1", resCol)]+ =<< cast "item1" resCol ADouble q+ return (q', [Col 1 ADouble], emptyPlan )+compileAppE1 (App _ (Var _ "splitAt") (ParExpr _ e1)) (q2, cs2, ts2) =+ do+ (q1, [Col 1 AInt], _ts1) <- coreToAlgebra e1+ let projPairs = zip (leafNames cs2) (leafNames cs2) + q2' <- absPos q2 cs2+ q' <- oper ">" resCol posPrime ordCol+ =<< cast "pos" posPrime intT+ =<< eqJoin "iter" iterPrime q2'+ =<< proj [(ordCol, "item1"), (iterPrime, "iter")] q1+ ql <- proj (("iter", "iter"):("pos", "pos"):projPairs)+ =<< select resColPrime + =<< notC resColPrime resCol q'+ qr <- proj (("iter", "iter"):("pos", "pos"):projPairs)+ =<< select resCol q'+ loop <- getLoop+ q'' <- attach "pos" natT (nat 1)+ =<< proj [("iter", "iter"), ("item1", "iter"), ("item2", "iter")] loop+ return (q'', [Col 1 ASur, Col 2 ASur], SubPlan $ M.fromList [(1, (ql, cs2, ts2)), (2, (qr, cs2, ts2))])+compileAppE1 (App _ (Var _ "take") (ParExpr _ e1)) (q2, cs2, ts2) =+ do+ (q1, [Col 1 AInt], _ts) <- coreToAlgebra e1+ q2' <- absPos q2 cs2+ let csProj = zip (leafNames cs2) (leafNames cs2)+ q <- proj (("iter", "iter"):("pos", "pos"):csProj) + =<< select resColPrimePrime+ =<< oper "||" resColPrimePrime resColPrime resCol + =<< oper "==" resColPrime oldCol posPrime + =<< oper ">" resCol oldCol posPrime + =<< cast "pos" posPrime intT+ =<< eqJoin "iter" iterPrime q2' + =<< proj [(iterPrime, "iter"), (oldCol, "item1")] q1+ return (q, cs2, ts2)+compileAppE1 (App _ (Var _ "drop") (ParExpr _ e1)) (q2, cs2, ts2) =+ do+ (q1, [Col 1 AInt], _ts) <- coreToAlgebra e1+ q2' <- absPos q2 cs2+ let csProj = zip (leafNames cs2) (leafNames cs2)+ q <- proj (("iter", "iter"):("pos", "pos"):csProj) + =<< select resCol+ =<< oper ">" resCol posPrime oldCol + =<< cast "pos" posPrime intT+ =<< eqJoin "iter" iterPrime q2' + =<< proj [(iterPrime, "iter"), (oldCol, "item1")] q1+ return (q, cs2, ts2)+compileAppE1 (Var _ "last") (q1, cs1, ts1) =+ do+ let csProj = zip (leafNames cs1) (leafNames cs1)+ q' <- eqTJoin [("iter", iterPrime), ("pos", resCol)] (("iter", "iter"):("pos", "pos"):csProj) q1+ =<< proj [(resCol, resCol), (iterPrime, "iter")]+ =<< aggr [(Max, resCol, Just "pos")] (Just "iter") q1+ return (q', cs1, ts1)+compileAppE1 (Var _ "init") (q1, cs1, ts1) =+ do+ let csProj = zip (leafNames cs1) (leafNames cs1)+ q <- proj (("iter", "iter"):("pos","pos"):csProj)+ =<< select resColPrime+ =<< oper ">" resColPrime resCol "pos" + =<< eqJoin "iter" iterPrime q1+ =<< proj [(resCol, resCol), (iterPrime, "iter")] + =<< aggr [(Max, resCol, Just "pos")] (Just "iter") q1+ return (q, cs1, ts1)+compileAppE1 (Var _ "null") (q1, _cs1, _ts1) =+ do+ loop <- getLoop+ notEmpty <- distinct =<< proj [("iter", "iter")] q1+ empty <- difference loop notEmpty+ notEmpty' <- attach "item1" boolT (bool False) notEmpty+ q <- attach "pos" natT (nat 1) + =<< union notEmpty'+ =<< attach "item1" boolT (bool True) empty+ return (q, [Col 1 ABool], emptyPlan) +compileAppE1 (Var _ "unBox") (q, [Col 1 ASur], ts) = + do+ let (q', cs', ts') = getPlan 1 ts+ let csProj = zip (leafNames cs') (leafNames cs')+ q'' <- proj (("iter", iterPrime):("pos","pos"):csProj)+ =<< eqJoin "iter" resCol q'+ =<< proj [(iterPrime, "iter"),(resCol, "item1")] q+ return (q'', cs', ts')+compileAppE1 (App _ (App _ (Var _ "groupWith") e1@(ParAbstr _ _ _)) e2@(ParAbstr _ _ _)) (q3, cs3, ts3) =+ do+ gam <- getGamma+ (qv', qv, _map', loop', gam') <- mapForward gam q3 cs3+ (q1, cs1, ts1) <- withContext gam' loop' $ compileLambda [(qv, cs3, ts3)] e1+ (q2, cs2, _ts2) <- withContext gam' loop' $ compileLambda [(qv, cs3, ts3)] e2+ let offSet = colSize cs1+ let cs2' = incrCols offSet cs2+ let projPairs1 = zip (leafNames cs1) (leafNames cs1)+ let projPairs2 = zip (leafNames cs2') (leafNames cs2)+ q1' <- proj ((iterR, "iter"):projPairs1) q1+ q2' <- proj ((iterPrime, "iter"):projPairs2) q2+ qs <- eqJoin iterR iterPrime q1' q2'+ qvs <- proj [("iter", "iter"), ("pos", "pos"), (inner, inner)] qv'+ q <- rowrank resCol (map (\ki -> (ki, Asc)) ((:) "iter" $ leafNames cs2'))+ =<< eqJoin inner iterPrime qvs qs+ let newCol = (+) 1 $ colSize cs2+ let projPairs2' = zip (leafNames cs2) (leafNames cs2')+ qout <- distinct =<< proj (("iter", "iter"):("pos", resCol):("item" ++ show newCol, resCol):projPairs2') q+ qin <- proj (("iter", resCol):("pos", "pos"):projPairs1) q+ let cs = [NCol "1" cs2, NCol "2" [Col newCol surT]]+ let ts = subPlan newCol (qin, cs1, ts1)+ return (qout, cs, ts)+compileAppE1 (App t2 (App t1 (Var mt "groupByN") e1) e2) e3 = compileAppE1 (App t2 (App t1 (Var mt "groupBy") e1) e2) e3+compileAppE1 (App t2 (App t1 (Var mt "groupBy'") e1) e2) e3 = compileAppE1 (App t2 (App t1 (Var mt "groupBy") e1) e2) e3+compileAppE1 (App t2 (App t1 (Var mt "groupBy1") e1) e2) e3 = compileAppE1 (App t2 (App t1 (Var mt "groupBy") e1) e2) e3+compileAppE1 (App t2 (App t1 (Var mt "groupBy2") e1) e2) e3 = compileAppE1 (App t2 (App t1 (Var mt "groupBy") e1) e2) e3+compileAppE1 (App t2 (App t1 (Var mt "groupBy3") e1) e2) e3 = compileAppE1 (App t2 (App t1 (Var mt "groupBy") e1) e2) e3+compileAppE1 (App t2 (App t1 (Var mt "groupBy4") e1) e2) e3 = compileAppE1 (App t2 (App t1 (Var mt "groupBy") e1) e2) e3+compileAppE1 (App t2 (App t1 (Var mt "groupBy5") e1) e2) e3 = compileAppE1 (App t2 (App t1 (Var mt "groupBy") e1) e2) e3+compileAppE1 (App t2 (App t1 (Var mt "groupBy6") e1) e2) e3 = compileAppE1 (App t2 (App t1 (Var mt "groupBy") e1) e2) e3+compileAppE1 (App _ (App _ (Var _ "groupBy") e1@(ParAbstr _ _ _)) e2@(ParAbstr _ _ _)) (q3, cs3, ts3) =+ do+ gam <- getGamma+ (qv', qv, _map', loop', gam') <- mapForward gam q3 cs3+ (q1, cs1, ts1) <- withContext gam' loop' $ compileLambda [(qv, cs3, ts3)] e1+ (q2, cs2, _ts2) <- withContext gam' loop' $ compileLambda [(qv, cs3, ts3)] e2+ let offSet = colSize cs1+ let cs2' = incrCols offSet cs2+ let projPairs1 = zip (leafNames cs1) (leafNames cs1)+ let projPairs2 = zip (leafNames cs2') (leafNames cs2)+ q1' <- proj ((iterR, "iter"):projPairs1) q1+ q2' <- proj ((iterPrime, "iter"):projPairs2) q2+ qs <- eqJoin iterR iterPrime q1' q2'+ qvs <- proj [("iter", "iter"), ("pos", "pos"), (inner, inner)] qv'+ q <- rowrank resCol (map (\ki -> (ki, Asc)) ((:) "iter" $ leafNames cs2'))+ =<< eqJoin inner iterPrime qvs qs+ let nrFields = length cs1+ let projOut = zip ["item" ++ show i | i <- [1..nrFields]] $ repeat resCol+ qout <- distinct =<< proj (("iter", "iter"):("pos", resCol):projOut) q+ (ts, cs) <- makeSubPlan 1 cs1 ts1 q+ return (qout, cs, ts)+compileAppE1 e1 _ = error $ "Not implemented yet: " ++ show e1 +++makeSubPlan :: Int -> Columns -> SubPlan -> AlgNode -> GraphM (SubPlan, Columns)+makeSubPlan 1 [Col _ t] (SubPlan ts) q = do+ qi <- proj [("iter", resCol),("pos", posPrime),("item1", "item1")] q+ let tsi = case M.lookup 1 ts of+ Nothing -> emptyPlan+ (Just p) -> subPlan 1 p+ return (subPlan 1 (qi, [Col 1 t], tsi), [Col 1 surT])+makeSubPlan i ((NCol n csi):css) (SubPlan ts) q = do+ (SubPlan ts', cs') <- makeSubPlan (i + 1) css (SubPlan ts) q+ let (csi', d) = decrCols csi+ let ln = leafNumbers csi'+ let projPairs = zip (leafNames csi') (leafNames csi)+ qi <- proj (("iter", resCol):("pos", "pos"):projPairs) q+ let tsi = SubPlan $ M.fromList [(l, ts M.! (l + d)) | l <- ln, isJust $ M.lookup (l + d) ts]+ return (SubPlan $ M.insert i (qi, csi', tsi) ts', (NCol n [Col i surT]):cs')+ +makeSubPlan _ [] _ _ = return (emptyPlan, [])+makeSubPlan _ _ _ _ = $impossible+ +-- | Compile a lambda where the argument variable is bound to the given expression +compileLambda :: [AlgRes] -> Param -> GraphM AlgRes+compileLambda args (ParAbstr _ xs e) = let pairs = zip xs args+ in foldr (\(v, a) -> withBinding v a) (coreToAlgebra e) pairs+compileLambda _ p = $impossible++-- | Transform gamma for map function +algResv :: AlgNode -> (String, AlgRes) -> GraphM (String, AlgRes)+algResv m (n, (q, cs, ts)) = do+ let projPairs = zip (leafNames cs) (leafNames cs)+ q' <- proj (("iter", inner):("pos","pos"):projPairs) =<< eqJoin "iter" outer q m+ return (n, (q', cs, ts))++keys :: SubPlan -> [String]+keys (SubPlan ts) = map (\i -> "item" ++ show i) $ M.keys ts +++mergeTableStructure :: AlgNode -> SubPlan -> SubPlan -> GraphM SubPlan+mergeTableStructure qo (SubPlan ts1') (SubPlan ts2') | M.null ts1' = return $ SubPlan ts2'+ | M.null ts2' = return $ SubPlan ts1'+ | otherwise = do+ rs <- mapM mergeBinds items+ return $ SubPlan $ M.fromList rs + where+ items = M.toList ts1'+ mergeBinds :: (Int, AlgRes) -> GraphM (Int, AlgRes)+ mergeBinds (i, (q1, cs1, ts1)) = do+ let (q2, _cs2, ts2) = case M.lookup i ts2' of+ Nothing -> error "jikes"+ Just a -> a+ let ks = keys ts1+ let cols = leafNames cs1+ let colsDiff = cols L.\\ ks+ let projPairs = zip cols cols+ let projPairsD = zip colsDiff colsDiff+ let projPairsKs = zip ks $ repeat iterPrime+ n1 <- attach ordCol natT (nat 1) q1+ n2 <- attach ordCol natT (nat 2) q2+ qo'' <- proj [(ordPrime, ordCol), (iterR, iterPrime), (oldCol, "item" ++ show i)] qo+ qo' <- eqTJoin [(ordPrime, ordCol), (oldCol, "iter")] + (("iter", "iter"):(iterR, iterR):("pos", "pos"):(ordCol, ordCol):projPairs)+ qo''+ =<< union n1 n2+ q <- rownum iterPrime ["iter", ordCol, "pos"] Nothing qo'+ qr <- proj ((iterPrime, iterPrime):(ordCol, ordCol):projPairs) q+ q' <- proj (("iter", iterR):("pos", "pos"):(projPairsD ++ projPairsKs)) q+ ts' <- mergeTableStructure qr ts1 ts2+ return (i, (q', cs1, ts'))+ +mergeTableStructureFirst :: AlgNode -> SubPlan -> SubPlan -> GraphM SubPlan+mergeTableStructureFirst qo (SubPlan ts1') (SubPlan ts2') + | M.null ts1' = return $ SubPlan ts2'+ | M.null ts2' = return $ SubPlan ts1'+ | otherwise= do+ rs <- mapM mergeBinds items+ return $ SubPlan $ M.fromList rs+ where+ items = M.toList ts1'+ mergeBinds :: (Int, AlgRes) -> GraphM (Int, AlgRes)+ mergeBinds (i, (q1, cs1, ts1)) = do + let (q2, _cs2, ts2) = ts2' M.! i+ let ks = keys ts1+ let cols = leafNames cs1+ let colsDiff = cols L.\\ ks+ let projPairs = zip cols cols+ let projPairsD = zip colsDiff colsDiff+ let projPairsKs = zip ks $ repeat iterPrime+ qo'' <- (proj [(ordPrime, ordCol),(iterR, iterPrime),(oldCol, "item" ++ show i)] qo)+ qo' <- eqTJoin [(ordPrime, ordCol), (oldCol, "iter")] + (("iter", "iter"):(iterR,iterR):("pos", "pos"):(ordCol, ordCol):(iterPrime, iterPrime) : projPairs) + qo''+ =<< rownum iterPrime ["iter", ordCol, "pos"] Nothing+ =<< flip union q2 =<< attach ordCol natT (nat 1) q1+ qr <- proj ((iterPrime, iterPrime):(ordCol, ordCol):projPairs) qo'+ q' <- proj (("iter", iterR):("pos", "pos"):(projPairsD ++ projPairsKs)) qo'+ ts' <- mergeTableStructureFirst qr ts1 ts2+ return (i, (q', cs1, ts'))+ ++mergeTableStructureLast :: Int -> SubPlan -> GraphM SubPlan+mergeTableStructureLast n (SubPlan ts1') = do+ rs <- mapM updateBinds items+ return $ SubPlan $ M.fromList rs+ where+ items = M.toList ts1'+ updateBinds :: (Int, AlgRes) -> GraphM (Int, AlgRes)+ updateBinds (i, (q1, cs1, ts1)) = do+ q <- attach ordCol natT (nat $ toInteger n) q1+ ts <- mergeTableStructureLast n ts1+ return (i, (q, cs1, ts))+ +mergeTableStructureSeq :: Int -> SubPlan -> SubPlan -> GraphM SubPlan+mergeTableStructureSeq n (SubPlan ts1') (SubPlan ts2') + | M.null ts1' = return $ SubPlan ts2'+ | M.null ts2' = return $ SubPlan ts1'+ | otherwise= do+ rs <- mapM mergeBinds items+ return $ SubPlan $ M.fromList rs+ where+ items = M.toList ts1'+ mergeBinds :: (Int, AlgRes) -> GraphM (Int, AlgRes)+ mergeBinds (i, (q1, cs1, ts1)) = do+ let (q2, _cs2, ts2) = ts2' M.! i+ q <- flip union q2 + =<< attach ordCol natT (nat $ toInteger n) q1+ ts <- mergeTableStructureSeq n ts1 ts2+ return (i, (q, cs1, ts))++-- Compilation for the first element of a list.+-- For optimisation purposes we distinguish three cases:+-- Singleton lists: compile these if they were just single values+-- A list where the second element is also created through a list constructor+-- that particular case allows for optimising on the rank operator, it is+-- compiled to algebra in the listSequence function that does not perform rank.+-- A list where the tail is the result of a computation, the tail is compiled as a+-- normal expression. The result get an ord column attached and the is unified+-- with the head of the list and then ranked. +listFirst :: CoreExpr -> GraphM AlgRes+listFirst (Cons _ e1 (Nil _)) = coreToAlgebra e1+listFirst (Cons _ e1 e2@(Cons _ _ _)) = do+ (q1, cs1, ts1) <- coreToAlgebra e1+ (q2, _cs2, ts2) <- listSequence e2 2+ let cols = leafNames cs1+ let ks = keys ts1+ let colsDiff = cols L.\\ ks+ let projPairs = (zip colsDiff colsDiff) ++ (zip ks $ repeat iterPrime) + q' <- rownum iterPrime ["iter", ordCol, "pos"] Nothing+ =<< rank posPrime [(ordCol, Asc), ("pos", Asc)] + =<< flip union q2 =<< attach ordCol natT (nat 1) q1+ q <- proj (("iter", "iter"):("pos", posPrime) : projPairs) q'+ ts <- mergeTableStructureFirst q' ts1 ts2+ return (q, cs1, ts) +listFirst (Cons _ e1 e2) = do+ (q1, cs1, ts1) <- coreToAlgebra e1+ (q2, _cs2, ts2) <- coreToAlgebra e2+ let cols = leafNames cs1+ let ks = keys ts1+ let colsDiff = cols L.\\ ks+ let projPairs = (zip colsDiff colsDiff) ++ (zip ks $ repeat iterPrime)+ n1 <- attach ordCol natT (nat 1) q1+ q' <- rownum iterPrime ["iter", ordCol, "pos"] Nothing+ =<< rank posPrime [(ordCol, Asc), ("pos", Asc)]+ =<< union n1 + =<< attach ordCol natT (nat 2) q2+ qr <- proj ((iterPrime, iterPrime):(ordCol, ordCol):(zip cols cols)) q'+ q <- proj (("iter", "iter"):("pos", posPrime):projPairs) q'+ ts <- mergeTableStructure qr ts1 ts2+ return (q, cs1, ts)+listFirst _ = $impossible+++-- List sequence, doesn't perform the rank operation, that is carried out by listFirst.+-- Three cases with similar motivation as listFirst.+listSequence :: CoreExpr -> Int -> GraphM AlgRes+listSequence (Cons _ e1 (Nil _)) n = do+ (q1, cs1, ts1) <- coreToAlgebra e1+ n1 <- attach ordCol natT (nat $ toEnum n) q1+ ts <- mergeTableStructureLast n ts1+ return (n1, cs1, ts)+listSequence (Cons _ e1 e2@(Cons _ _ _)) n = do+ (q1, cs1, ts1) <- coreToAlgebra e1+ (q2, _cs2, ts2) <- listSequence e2 $ n + 1+ n1 <- attach ordCol natT (nat $ toEnum n) q1+ n2 <- union n1 q2+ ts <- mergeTableStructureSeq n ts1 ts2+ return (n2, cs1, ts)+listSequence c@(Cons _ _ _) n = do+ (q, cs, ts) <- listFirst c+ n1 <- attach ordCol natT (nat $ toEnum n) q+ ts' <- mergeTableStructureLast n ts+ return (n1, cs, ts')+listSequence _ _ = $impossible+ +-- Transform a record element into algebraic plan +recElemToAlgebra :: RecElem -> GraphM AlgRes+recElemToAlgebra (RecElem _ n e) = do+ (q1, cs1, ts1) <- coreToAlgebra e+ return (q1, [NCol n cs1], ts1)++-- Transform a record into an algebraic plan +recElemsToAlgebra :: GraphM AlgRes -> RecElem -> GraphM AlgRes+recElemsToAlgebra alg2 el = do+ (q1, cs1, (SubPlan ts1)) <- alg2+ (q2, cs2, (SubPlan ts2)) <- recElemToAlgebra el+ let offSet = colSize cs1+ let cs2' = incrCols offSet cs2+ let projPairs = zip (leafNames cs2') (leafNames cs2)+ let ts = SubPlan $ M.union ts1 $ M.mapKeysMonotonic (+ offSet) ts2+ n1 <- proj ((mkPrefixIter 1, "iter"):projPairs) q2+ n2 <- eqJoin "iter" (mkPrefixIter 1) q1 n1+ let projPairs' = zip (leafNames cs1) (leafNames cs1) ++ zip (leafNames cs2') (leafNames cs2')+ n3 <- proj (("iter", "iter"):("pos", "pos"):projPairs') n2+ return (n3, cs1 ++ cs2', ts)++-- map forward transforms the environment etc into the versions needed to compute in+-- a loop context. The result is (qv', qv, mapv, loopv, Gamv)+mapForward :: Gam -> AlgNode -> Columns -> GraphM (AlgNode, AlgNode, AlgNode, AlgNode, Gam)+mapForward gam q cs = do+ let csProj = zip (leafNames cs) (leafNames cs)+ qv' <- rownum inner ["iter", "pos"] Nothing q+ qv <- proj (("iter", inner):("pos", posPrime):csProj)+ =<< attach posPrime natT (nat 1) qv'+ mapv <- proj [(outer, "iter"), (inner, inner), (posPrime, "pos")] qv'+ loopv <- proj [("iter",inner)] qv'+ gamV <- transformGam algResv mapv gam+ return (qv', qv, mapv, loopv, gamV)++-- clean innerPlans+cleanInner :: AlgNode -> SubPlan -> GraphM SubPlan+cleanInner q (SubPlan ps) = do + ps' <- sequence + [ do + let item = "item" ++ show c+ qo <- proj [(resCol, item)] q+ let projPairs = zip (leafNames cs') (leafNames cs')+ q'' <- proj (("iter", "iter"):("pos","pos"):projPairs)+ =<< eqJoin resCol item qo q' + ts'' <- cleanInner q'' ts'+ return (c, (q'', cs', ts'')) | (c, (q', cs', ts')) <- M.toList ps]+ return (SubPlan $ M.fromList ps')+ +-- Recalculate the position column, making it densely populated after this operation+absPos :: AlgNode -> Columns -> GraphM AlgNode+absPos q cs = let projPairs = zip (leafNames cs) (leafNames cs)+ in proj (("iter", "iter"):("pos", "pos"):projPairs) + =<< rownum "pos" [posPrime] (Just "iter")+ =<< proj (("iter", "iter"):(posPrime, "pos"):projPairs) q+ +-- Function to transform the column structure++--From a typedcore column list to algebraic columns+coreCol2AlgCol :: [T.Column] -> Columns+coreCol2AlgCol cols = map (\(Column s t, i) -> NCol s $ fst $ typeToCols t i) cols'+ where+ cols' = zip cols [1..]++--Translate core keys to algebraic keys+key2Key :: Columns -> [Key] -> KeyInfos+key2Key cs ks = map (\(Key k) -> map (\ki -> case getCol ki cs of+ [(Col i _)] -> "item" ++ show i+ [] -> $impossible+ (NCol _ _) : _ -> $impossible+ (Col _ _) : (_ : _) -> $impossible) k ) ks++-- Get all the column names from the structure +leafNames :: Columns -> [String]+leafNames cs = map (\c -> case c of+ (Col i _) -> "item" ++ show i+ _ -> error "Named column not allowed in leafNames") $ colLeafs cs++leafNumbers :: Columns -> [Int]+leafNumbers cs = map (\c -> case c of+ (Col i _) -> i+ _ -> error "Named column not allowed in LeafNumbers") $ colLeafs cs++-- Get all the leaf columns, that is the columns that are actually a column+colLeafs :: Columns -> Columns+colLeafs (c@(Col _ _):xs) = (:) c $ colLeafs xs+colLeafs ((NCol _ cs):xs) = colLeafs cs ++ colLeafs xs+colLeafs [] = []++-- Count the number of columns+colSize :: Columns -> Int+colSize = length . colLeafs++-- Increment the column numbers by a given amount+incrCols :: Int -> Columns -> Columns+incrCols inc ((Col i t):xs) = (Col (i + inc) t):(incrCols inc xs)+incrCols inc ((NCol x i):xs) = (NCol x (incrCols inc i)):(incrCols inc xs)+incrCols _ [] = [] ++-- Find the lowest column number+minCol :: Columns -> Int+minCol c = minimum $ map (\c' -> case c' of+ (Col i _) -> i+ _ -> error "Named column not expected in minCol") $ colLeafs c++-- Decrement the column numbers so that the lowest column number is 1 after applying+decrCols :: Columns -> (Columns, Int)+decrCols cols = let minV = minCol cols+ in (decr' (minV - 1) cols, minV - 1)+ where+ decr' :: Int -> Columns -> Columns+ decr' decr ((Col i t):xs) = (flip Col t $ i - decr) : (decr' decr xs)+ decr' decr ((NCol x i):xs) = (NCol x $ decr' decr i) : (decr' decr xs)+ decr' _ [] = []++-- Find the columns associated with a record label+getCol :: String -> Columns -> Columns+getCol n cs = getCol' cs+ where+ getCol' :: Columns -> Columns+ getCol' ((Col _ _):xs) = getCol' xs+ getCol' ((NCol x i):xs) | x == n = i+ | otherwise = getCol' xs+ getCol' [] = error $ show n ++ " in " ++ show cs --[]++-- Transform Columns info into schema info for algebraic compilation+colsToSchema :: Columns -> SchemaInfos+colsToSchema ((Col i t):xs) = (:)("item" ++ show i, t) $ colsToSchema xs+colsToSchema ((NCol _ cs):xs) = colsToSchema cs ++ colsToSchema xs+colsToSchema [] = []++-- Transform a type to columns structure+typeToCols :: FType -> Int -> (Columns, Int)+typeToCols (FRec recs) i = recsToCols recs i+typeToCols FInt i = ([Col i AInt], i + 1)+typeToCols FBool i = ([Col i ABool], i + 1)+typeToCols FFloat i = ([Col i ADouble], i + 1)+typeToCols FString i = ([Col i AStr], i + 1)+typeToCols FUnit i = ([Col i AInt], i + 1)+typeToCols (FList _) i = ([Col i ASur], i + 1)+typeToCols (FVar _) i = ([Col i ANat], i + 1)+typeToCols _ _ = $impossible++-- Compile a record type to a column structure+recsToCols :: [(RLabel, FType)] -> Int -> (Columns, Int)+recsToCols ((RLabel s, ty):xs) i = let (cs, i') = typeToCols ty i+ (cs', i'') = recsToCols xs i'+ in ((NCol s cs):cs', i'')+recsToCols [] i = ([], i)+recsToCols ((RGen _, _) : _) _ = $impossible+recsToCols ((RVar _, _) : _) _ = $impossible
+ src/Database/Ferry/TypedCore/Convert/Specialize.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE TemplateHaskell #-}+{-| Provides a function that can replace groupByN occurences by a more specific one-}+module Database.Ferry.TypedCore.Convert.Specialize where++import Database.Ferry.TypedCore.Convert.Traverse+import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.Impossible++groupNSpecialize :: CoreExpr -> CoreExpr+groupNSpecialize = traverse f+ where+ f :: FoldCore CoreExpr Param RecElem+ f = idFoldCore {varF = fnS}+ fnS :: Qual FType -> String -> CoreExpr+ fnS t s = case s of+ "groupByN" -> case typeSize t of+ n | 0 < n && n <= 6 -> Var t $ "groupBy" ++ (show n)+ | otherwise -> Var t "groupByN"+ _ -> (Var t s)+ typeSize :: Qual FType -> Int+ typeSize (_ :=> (FFn (FFn _ t2) _)) = case t2 of+ (FRec r) -> length r+ _ -> 0+ typeSize _ = $impossible
+ src/Database/Ferry/TypedCore/Convert/Traverse.hs view
@@ -0,0 +1,65 @@+{- | Provides a traverse method that given functions for parts of the AST traverses the AST and applies the function where appropriate -}+module Database.Ferry.TypedCore.Convert.Traverse where+ +import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.Common.Data.Base+import Control.Monad++-- | Datatype that contains the functions that are needed for a traversal+data FoldCore b p r = FoldCore {binOpF :: Qual FType -> Op -> b -> b -> b+ ,constantF :: Qual FType -> Const -> b+ ,varF :: Qual FType -> String -> b+ ,appF :: Qual FType -> b -> p -> b+ ,letF :: Qual FType -> String -> b -> b -> b+ ,recF :: Qual FType -> [r] -> b+ ,consF :: Qual FType -> b -> b -> b+ ,nilF :: Qual FType -> b+ ,elemF :: Qual FType -> b -> String -> b+ ,tableF :: Qual FType -> String -> [Column] -> [Key] -> b+ ,ifF :: Qual FType -> b -> b -> b -> b+ ,pExprF :: Qual FType -> b -> p+ ,pAbstrF :: Qual FType -> [String] -> b -> p+ ,rRecEF :: Qual FType -> String -> b -> r}++-- | Identity traversel+idFoldCore :: FoldCore CoreExpr Param RecElem+idFoldCore = FoldCore BinOp Constant Var App Let Rec Cons Nil Elem Table If ParExpr ParAbstr RecElem ++-- | Monadic traversal+mFoldCore :: Monad m => FoldCore (m CoreExpr) (m Param) (m RecElem)+mFoldCore = FoldCore (\t o -> liftM2 (BinOp t o))+ (\t c -> return $ Constant t c)+ (\t s -> return $ Var t s)+ (\t -> liftM2 $ App t)+ (\t s -> liftM2 $ Let t s)+ (\t rs -> do+ rs' <- sequence rs+ return $ Rec t rs')+ (\t -> liftM2 $ Cons t)+ (\t -> return $ Nil t)+ (\t e s -> do+ e' <- e+ return $ Elem t e' s)+ (\t s c k -> return $ Table t s c k)+ (\t -> liftM3 $ If t)+ (\t -> liftM $ ParExpr t)+ (\t p -> liftM $ ParAbstr t p)+ (\t s -> liftM $ RecElem t s)+ ++-- | This function traverses the whole CoreExpr tree and applies the given function at every node after+-- | that the function is applied to all its children.+traverse :: (FoldCore b p r) -> CoreExpr -> b+traverse f (BinOp t o e1 e2) = (binOpF f) t o (traverse f e1) $ traverse f e2+traverse f (Constant t c) = (constantF f) t c+traverse f (Var t s) = (varF f) t s+traverse f (App t e1 (ParExpr t2 e2)) = (appF f) t (traverse f e1) $ (pExprF f) t2 $ traverse f e2+traverse f (App t e1 (ParAbstr t2 p e)) = (appF f) t (traverse f e1) $ (pAbstrF f) t2 p $ traverse f e+traverse f (Let t s e1 e2) = (letF f) t s (traverse f e1) $ traverse f e2+traverse f (Rec t els) = (recF f) t $ map (\(RecElem t' s e) -> (rRecEF f) t' s $ traverse f e) els+traverse f (Cons t e1 e2) = (consF f) t (traverse f e1) $ traverse f e2+traverse f (Nil t) = (nilF f) t+traverse f (Elem t e s) = (elemF f) t (traverse f e) s+traverse f (If t e1 e2 e3) = (ifF f) t (traverse f e1) (traverse f e2) $ traverse f e3+traverse f (Table t s c k) = (tableF f) t s c k
+ src/Database/Ferry/TypedCore/Data/Instances.hs view
@@ -0,0 +1,155 @@+{- | Some typeclass instances belonging to the datatypes associated with typed core -}+{-# LANGUAGE TypeSynonymInstances #-}+module Database.Ferry.TypedCore.Data.Instances where+ +import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.TypedCore.Data.Substitution+import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Data.TypeFunction++import qualified Data.Set as S+import qualified Data.Map as M++{- | Run a substitution over a simple type-}+instance Substitutable FType where+ apply s (FList t) = FList $ apply s t + apply s (FFn t1 t2) = FFn (apply s t1) (apply s t2)+ apply s (FRec rs) = FRec $ map (\(n, t) -> (apply s n, apply s t)) rs+ apply s (FTF f t) = evalTy $ FTF f $ apply s t+ apply (t, _) v@(FVar _) = case M.notMember v t of+ True -> v+ False -> t M.! v+ apply (t, _) v@(FGen _) = case M.notMember v t of+ True -> v+ False -> t M.! v+ apply _ t = t -- If the substitution is not applied to a container type or variable just stop primitives cannot be substituted++{- | Run a substitution over a qualified type -}+instance Substitutable t => Substitutable (Qual t) where+ apply s (preds:=> t) = (map (apply s) preds) :=> apply s t++{- | Run a substitution over a predicate -} +instance Substitutable Pred where+ apply s (IsIn c t) = IsIn c $ apply s t+ apply s (Has r n t) = Has (apply s r) n (apply s t) ++{- | Run a substitution over a typescheme, note that bound+variables are *NOT* touched by a substitution -} +instance Substitutable TyScheme where+ apply s (Forall i r t) = Forall i r $ apply s t++{- | Run a substitution over all types in the type environment -} +instance Substitutable TyEnv where+ apply s m = M.map (apply s) m++{- | Run a substitution over a list of substituable structures -} +instance Substitutable a => Substitutable [a] where+ apply s m = map (apply s) m++{- | Run a substitution over a typed AST -} +instance Substitutable CoreExpr where+ apply s (BinOp t o c1 c2) = BinOp (apply s t) o (apply s c1) (apply s c2)+-- apply s (UnaOp t o c) = UnaOp (apply s t) o (apply s c)+ apply s (Constant t c) = Constant (apply s t) c+ apply s (Var t x) = Var (apply s t) x+ apply s (App t c a) = App (apply s t) (apply s c) (apply s a)+ apply s (Let t x c1 c2) = Let (apply s t) x (apply s c1) (apply s c2)+ apply s (Rec t es) = Rec (apply s t) $ map (apply s) es+ apply s (Cons t c1 c2) = Cons (apply s t) (apply s c1) (apply s c2)+ apply s (Nil t) = Nil (apply s t)+ apply s (Elem t c f) = Elem (apply s t) (apply s c) f+ apply s (Table t n c k) = Table (apply s t) n c k+ apply s (If t c1 c2 c3) = If (apply s t) (apply s c1) (apply s c2) (apply s c3)++instance Substitutable Param where+ apply s (ParExpr t c) = ParExpr (apply s t) (apply s c)+ apply s (ParAbstr t pa c) = ParAbstr (apply s t) pa (apply s c)+ +instance Substitutable RecElem where+ apply s (RecElem t x c) = RecElem (apply s t) x (apply s c)++instance Substitutable RLabel where+ apply (_, r) v = case M.notMember v r of+ True -> v+ False -> r M.! v+ +{- * Instances of VarContainer class-}+ +instance VarContainer FType where+ ftv (FVar a) = S.singleton a+ ftv (FList t) = ftv t+ ftv (FRec s) = S.unions $ map (ftv . snd) s+ ftv (FFn t1 t2) = ftv t1 `S.union` ftv t2+ ftv _ = S.empty+ frv (FList t) = frv t+ frv (FRec s) = S.unions $ map (\(r,t) -> S.union (frv r) (frv t)) s+ frv (FFn t1 t2) = frv t1 `S.union` frv t2+ frv _ = S.empty + hasQVar (FList t) = hasQVar t+ hasQVar (FRec s) = and $ map (hasQVar . snd) s+ hasQVar (FFn t1 t2) = hasQVar t1 && hasQVar t2+ hasQVar (FGen _) = True+ hasQVar _ = False+ +instance VarContainer TyScheme where+ ftv (Forall _ _ t) = ftv t + frv (Forall _ _ t) = frv t+ hasQVar (Forall i _ _) = if i > 0 then True else False++instance VarContainer t => VarContainer (Qual t) where+ ftv (preds :=> t) = S.unions $ (ftv t):(map ftv preds)+ frv (preds :=> t) = S.unions $ (frv t):(map frv preds)+ hasQVar (preds :=> t) = (&&) (hasQVar t) $ and $ map hasQVar preds ++instance VarContainer Pred where+ ftv (IsIn _ t) = ftv t+ ftv (Has t _ t2) = ftv t `S.union` ftv t2+ frv (IsIn _ t) = frv t+ frv (Has t _ t2) = frv t `S.union` frv t2+ hasQVar (IsIn _ t) = hasQVar t+ hasQVar (Has t _ t2) = hasQVar t && hasQVar t2++instance VarContainer TyEnv where+ ftv m = S.unions $ M.elems $ M.map ftv m+ frv m = S.unions $ M.elems $ M.map frv m+ hasQVar m = and $ map (hasQVar . snd) $ M.assocs m+ +instance VarContainer RLabel where+ ftv _ = S.empty+ frv (RVar i) = S.singleton i+ frv _ = S.empty+ hasQVar (RGen _) = True+ hasQVar _ = False+ +instance HasType CoreExpr where+ typeOf (BinOp t _ _ _) = t+-- typeOf (UnaOp t o c) = t+ typeOf (Constant t _) = t+ typeOf (Var t _) = t+ typeOf (App t _ _) = t+ typeOf (Let t _ _ _) = t+ typeOf (Rec t _) = t+ typeOf (Cons t _ _) = t+ typeOf (Nil t) = t+ typeOf (Elem t _ _) = t+ typeOf (Table t _ _ _) = t+ typeOf (If t _ _ _) = t+ setType t (BinOp _ o c1 c2) = BinOp t o c1 c2+-- setType t (UnaOp _ o c) = UnaOp t o c+ setType t (Constant _ c) = Constant t c+ setType t (Var _ x) = Var t x + setType t (App _ c a) = App t c a + setType t (Let _ x c1 c2) = Let t x c1 c2+ setType t (Rec _ es) = Rec t es+ setType t (Cons _ c1 c2) = Cons t c1 c2+ setType t (Nil _) = Nil t+ setType t (Elem _ c f) = Elem t c f+ setType t (Table _ n c k) = Table t n c k+ setType t (If _ c1 c2 c3) = If t c1 c2 c3+ + +instance HasType Param where+ typeOf (ParExpr t _) = t+ typeOf (ParAbstr t _ _) = t+ setType t (ParExpr _ e) = ParExpr t e+ setType t (ParAbstr _ p e) = ParAbstr t p e
+ src/Database/Ferry/TypedCore/Data/Substitution.hs view
@@ -0,0 +1,19 @@+{- | Defines substitutions -}+{-# LANGUAGE TypeSynonymInstances #-}+module Database.Ferry.TypedCore.Data.Substitution where+ +import Database.Ferry.TypedCore.Data.Type++import qualified Data.Map as M++-- | A substitution is either a substitution over a type or over a label+type Subst = (TSubst, RSubst)+-- | A substitution is a mapping from a record label to a new record label+type RSubst = M.Map RLabel RLabel+-- | A substitution is a mapping from a type variable to a type+type TSubst = M.Map FType FType++-- | The class substitutable exposes a function that applies a substitution to+-- datatypes that are an instance of it.+class Substitutable a where+ apply :: Subst -> a -> a
+ src/Database/Ferry/TypedCore/Data/Type.hs view
@@ -0,0 +1,106 @@+{-| Type language -}+{-# LANGUAGE GADTs, TypeSynonymInstances #-}+module Database.Ferry.TypedCore.Data.Type where++import qualified Data.Set as S+import qualified Data.Map as M++type Ident = String++-- | Type environment is a mapping from identifiers to type schemes+type TyEnv = M.Map Ident TyScheme++type TyGens = Int+type RecGens = Int++-- | A type scheme represents a quantified type+data TyScheme where+ Forall :: TyGens -> RecGens -> Qual FType -> TyScheme+ deriving Show++infix 5 :=> ++-- | A qualified type is a type with some predicates ([predicates] :=> type)+data Qual t where+ (:=>) :: [Pred] -> t -> Qual t+ deriving Show++-- | Predicates relating to records+data Pred where+ IsIn :: String -> FType -> Pred -- | name `IsIn` t -> t is a record (or type variable) that contains at least a field name+ Has :: FType -> RLabel -> FType -> Pred -- | Similaar to IsIn but now with a type for the name+ deriving (Show, Eq)++-- | Type language +data FType where+ FGen :: Int -> FType -- | Generalised type variable+ FUnit :: FType -- | ()+ FInt :: FType -- | Int+ FFloat :: FType -- | Float+ FString :: FType -- | String+ FBool :: FType -- | Bool+ FList :: FType -> FType -- | [a]+ FVar :: Ident -> FType -- | a+ FRec :: [(RLabel, FType)] -> FType -- | {x1 :: t1, ..., xn :: tn} + FFn :: FType -> FType -> FType -- | t1 -> t2+ FTF :: FTFn -> FType -> FType -- | f t1+ deriving (Show, Eq, Ord)++-- | Is t a primitive type? +isPrim :: FType -> Bool+isPrim FInt = True+isPrim FFloat = True+isPrim FString = True+isPrim FBool = True+isPrim (FRec ls) = and $ map (isPrim . snd) ls+isPrim _ = False++-- | Language for record labels+data RLabel where+ RLabel :: String -> RLabel+ RGen :: Int -> RLabel -- | Generalised record label+ RVar :: String -> RLabel+ deriving (Show, Eq, Ord)++-- | Type functions +data FTFn where+ Tr :: FTFn+ Tr' :: FTFn+ deriving (Show, Eq, Ord)++-- * Function used to construct types +int :: FType+int = FInt+float :: FType+float = FFloat+string :: FType+string = FString+bool :: FType+bool = FBool+list :: FType -> FType+list t = FList t+var :: Ident -> FType+var i = FVar i+rec :: [(RLabel, FType)] -> FType+rec s = FRec s+fn :: FType -> FType -> FType+fn t1 t2 = FFn t1 t2+genT :: Int -> FType+genT i = FGen i ++infixr 6 .->++(.->) :: FType -> FType -> FType +t1 .-> t2 = fn t1 t2++-- | A varcontainer can contain type variables, or record variables+class VarContainer a where+ ftv :: a -> S.Set Ident+ frv :: a -> S.Set Ident+ hasQVar :: a -> Bool++-- | Everything that contains a type. +class HasType a where+ typeOf :: a -> Qual FType+ setType :: Qual FType -> a -> a+
+ src/Database/Ferry/TypedCore/Data/TypeClasses.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE TemplateHaskell #-}+module Database.Ferry.TypedCore.Data.TypeClasses where+ +import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.Compiler.Error.Error+import Database.Ferry.Impossible++import qualified Data.Map as M++-- Type Class stuff (based on M. P. Jones Typing Haskell in Haskell)++type Class = ([Ident], [Inst])+type Inst = Qual Pred++type ClassEnv = M.Map Ident Class++type ClassEnvTransformer = ClassEnv -> Either FerryError ClassEnv++infixr 5 <:>+(<:>) :: ClassEnvTransformer -> ClassEnvTransformer -> ClassEnvTransformer+(f <:> g) ce = do+ ce' <- f ce+ g ce'+ +defined :: Ident -> ClassEnv -> Bool+defined = M.member++addClass :: Ident -> [Ident] -> ClassEnvTransformer+addClass c sc ce+ | defined c ce = Left $ ClassAlreadyDefinedError c+ | any (not . flip defined ce) sc = Left $ SuperClassNotDefined c sc+ | otherwise = Right $ M.insert c (sc, []) ce+ +addInstance :: [Pred] -> Pred -> ClassEnvTransformer+addInstance ps p@(IsIn i _) ce | not (defined i ce) = Left $ ClassNotDefined i+ | otherwise = Right $ M.insert i (c, inst:is) ce + where + (c, is) = getClass i ce+ inst = ps :=> p +addInstance _ (Has _ _ _) _ = $impossible+ +getClass :: Ident -> ClassEnv -> Class+getClass i m = m M.! i++emptyClassEnv :: ClassEnv+emptyClassEnv = M.empty
+ src/Database/Ferry/TypedCore/Data/TypeFunction.hs view
@@ -0,0 +1,31 @@+{-| Handle the type functions related to records-}+module Database.Ferry.TypedCore.Data.TypeFunction where++import Database.Ferry.TypedCore.Data.Type++-- | Evaluate the type function application to a type that doesn't contain a function +evalTy :: FType -> FType+evalTy o@(FTF fn' t) = case applyTyFn fn' t of+ Right t' -> evalTy t'+ Left _ -> o+evalTy (FList t) = FList $ evalTy t+evalTy (FRec t) = FRec $ map (\(i,t') -> (i, evalTy t')) t+evalTy (FFn t1 t2) = FFn (evalTy t1) $ evalTy t2+evalTy t = t++-- | Apply a type function to a type+applyTyFn :: FTFn -> FType -> Either FType FType+applyTyFn Tr (FList t) = Right $ FList $ FList t+applyTyFn Tr (FRec ts) = Right $ FRec $ map (\(l, t) -> (l, FList t)) ts +applyTyFn Tr (FTF Tr' t) = Right $ t+applyTyFn Tr (FTF Tr t) = case applyTyFn Tr t of+ Right t' -> applyTyFn Tr t'+ Left t' -> Left $ FTF Tr t'+applyTyFn Tr (FVar v) = Left $ FTF Tr $ FVar v+applyTyFn Tr t = Left $ FTF Tr t+applyTyFn Tr' (FList (FList t)) = Right $ FList t+applyTyFn Tr' (FRec ts) = Right $ FRec $ map (\(l, t) -> (l, case t of + FList t' -> t'+ _ -> error "Not a list")) ts+applyTyFn Tr' (FTF Tr t) = Right t +applyTyFn Tr' _ = error "Cannot apply Tr'"
+ src/Database/Ferry/TypedCore/Data/TypedCore.hs view
@@ -0,0 +1,52 @@+{- | Datatypes describing typed AST -}+{-# LANGUAGE GADTs #-}+module Database.Ferry.TypedCore.Data.TypedCore where+ +import Database.Ferry.Common.Data.Base(Const)+import Database.Ferry.TypedCore.Data.Type++type Ident = String++data Op where+ Op :: String -> Op+ deriving (Show)++data CoreExpr where+ BinOp :: (Qual FType) -> Op -> CoreExpr -> CoreExpr -> CoreExpr+-- UnaOp :: (Qual FType) -> Op -> CoreExpr -> CoreExpr+ Constant :: (Qual FType) -> Const -> CoreExpr+ Var :: (Qual FType) -> String -> CoreExpr+ App :: (Qual FType) -> CoreExpr -> Param -> CoreExpr+ Let :: (Qual FType) -> String -> CoreExpr -> CoreExpr -> CoreExpr+ Rec :: (Qual FType) -> [RecElem] -> CoreExpr+ Cons :: (Qual FType) -> CoreExpr -> CoreExpr -> CoreExpr+ Nil :: (Qual FType) -> CoreExpr+ Elem :: (Qual FType) -> CoreExpr -> String -> CoreExpr+ Table :: (Qual FType) -> String -> [Column] -> [Key] -> CoreExpr+ If :: (Qual FType) -> CoreExpr -> CoreExpr -> CoreExpr -> CoreExpr+ deriving (Show)++data RecElem where+ RecElem :: (Qual FType) -> String -> CoreExpr -> RecElem+ deriving (Show)++data Param where+ ParExpr :: (Qual FType) -> CoreExpr -> Param+ ParAbstr :: (Qual FType) -> [String] -> CoreExpr -> Param+ deriving (Show)++{-+data Pattern where+ PVar :: String -> Pattern+ Pattern :: [String] -> Pattern+ deriving (Show)+-}++data Column where+ Column :: String -> FType -> Column+ deriving (Show)++data Key where+ Key :: [String] -> Key+ deriving (Show)+
+ src/Database/Ferry/TypedCore/Render/Dot.hs view
@@ -0,0 +1,122 @@+{- | Transform a typed core AST into a dot graph -}+module Database.Ferry.TypedCore.Render.Dot where++import Database.Ferry.Common.Render.Dot+import Database.Ferry.Common.Render.Pretty +import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.Common.Data.Base+import Database.Ferry.TypedCore.Render.Pretty()++import qualified Data.List as L++instance Dotify CoreExpr where+ dot e = runDot $ toDot e++toDot :: CoreExpr -> Dot Id+toDot (BinOp t o e1 e2) = do+ let o' = (\(Op op) -> op) o + nId <- node [Label $ SLabel o', Color Green, Shape Circle]+ tId <- typeToDot t+ id1 <- toDot e1+ id2 <- toDot e2+ edge nId [id1, id2, tId]+ return nId+toDot (Constant t c) = do+ let s = toString c+ nId <- node [Label $ SLabel s, Color Yellow, Shape Triangle]+ tId <- typeToDot t+ edge nId [tId]+ return nId+toDot (Var t i) = do+ nId <- node [Label $ SLabel i, Color Red, Shape Triangle]+ tId <- typeToDot t+ edge nId [tId]+ return nId+toDot (App t c ps) = do+ nId <- node [Label $ SLabel "$", Color Green, Shape Circle]+ tId <- typeToDot t+ fId <- toDot c+ pIds <- paramToDot ps+ edge nId [fId, pIds, tId]+ return nId+toDot (Let t s e1 e2) = do+ nId <- node [Label $ SLabel "Let", Color Blue, Shape Rect]+ tId <- typeToDot t+ id0 <- node [Label $ SLabel s, Color Red, Shape Rect, TextColor White]+ id1 <- toDot e1+ id2 <- toDot e2+ edge nId [id0, id1, id2, tId]+ return nId+toDot (Rec t es) = do+ nId <- node [Label $ SLabel "Rec", Color Blue, Shape Oval]+ tId <- typeToDot t+ eIds <- mapM recToDot es+ edge nId (eIds ++ [tId])+ return nId+toDot (Cons t e1 e2) = do+ nId <- node [Label $ SLabel "Cons", Color Blue, Shape Oval]+ tId <- typeToDot t+ eIdh <- toDot e1+ eIdt <- toDot e2+ edge nId [eIdh, eIdt, tId]+ return nId+toDot (Nil t) = do+ nId <- node [Label $ SLabel "Nil", Color Blue, Shape Oval]+ tId <- typeToDot t+ edge nId [tId]+ return nId+toDot (Elem t c s) = do+ nId <- node [Label $ SLabel ".", Color Green, Shape Circle]+ sId <- node [Label $ SLabel s, Color Red, Shape Triangle]+ tId <- typeToDot t+ cId <- toDot c+ edge nId [cId, sId, tId]+ return nId+toDot (Table ty n cs ks) = do+ let label = VLabel $ ((HLabel [SLabel "Table:", SLabel n])+ : [HLabel [SLabel $ n' ++ "::", SLabel $ prettyPrint t ] | (Column n' t) <- cs])+ ++ [SLabel $ keyToString k | k <- ks]+ nId <- node [Shape Rect, Label label, Color Yellow]+ tId <- typeToDot ty+ edge nId [tId]+ return nId+toDot (If t e1 e2 e3) = do+ nId <- node [Label $ SLabel "If", Color Blue, Shape Circle]+ tId <- typeToDot t+ eId1 <- toDot e1+ eId2 <- toDot e2+ eId3 <- toDot e3+ edge nId [eId1, eId2, eId3, tId]+ return nId+ ++paramToDot :: Param -> Dot Id+paramToDot (ParExpr _ e) = toDot e+paramToDot (ParAbstr t p e) = do+ nId <- node [Label $ SLabel "\\ ->", Color Blue, Shape Circle]+ tId <- typeToDot t+ pId <- node [Label $ SLabel (show p), Color Red, Shape Triangle]+ eId <- toDot e+ edge nId [pId, eId, tId]+ return nId++{- +patToDot :: Pattern -> Dot Id+patToDot (PVar s) = node [Label $ SLabel s, Color Red, Shape Triangle]+patToDot (Pattern s) = node [Label $ SLabel $ "(" ++ (concat $ L.intersperse ", " s) ++ ")", Color Red, Shape Triangle]+-}+ +recToDot :: RecElem -> Dot Id+recToDot (RecElem t s e) = do+ nId <- node [Label $ SLabel s, Color Red, Shape Oval]+ tId <- typeToDot t+ eId <- toDot e+ edge nId [eId, tId]+ return nId++keyToString :: Key -> String+keyToString (Key ks) = "(" ++ (concat $ L.intersperse ", " ks) ++ ")"++typeToDot :: Qual FType -> Dot Id+typeToDot t = node [Label $ SLabel $ prettyPrint t, Color Gray, Shape Rect]
+ src/Database/Ferry/TypedCore/Render/Pretty.hs view
@@ -0,0 +1,44 @@+{- | Pretty print a type -}+{-# LANGUAGE FlexibleInstances #-}+module Database.Ferry.TypedCore.Render.Pretty where++import Char +import Database.Ferry.Common.Render.Pretty+import Database.Ferry.TypedCore.Data.Type++instance Pretty FType where+ pretty FUnit _ = "()"+ pretty FInt _ = "Int"+ pretty FFloat _ = "Float"+ pretty FString _ = "String"+ pretty FBool _ = "Bool"+ pretty (FList a) _ = "[" ++ pretty a 0 ++ "]"+ pretty (FVar a) _ = "a" ++ a+ pretty (FRec a) _ = case fst $ head a of+ RLabel r -> case and $ map isDigit $ r of+ True -> "(" ++ mapIntersperseConcat (flip pretty 1) ", " (map snd a) ++ ")"+ False -> "{" ++ mapIntersperseConcat (flip pretty 1) ", " a ++ "}"+ _ -> "{" ++ mapIntersperseConcat (flip pretty 1) ", " a ++ "}"+ pretty (FFn t1 t2) _ = "(" ++ pretty t1 0 ++ ") -> " ++ pretty t2 0+ pretty (FGen i) _ = "a" ++ show i+ pretty (FTF f t) _ = "(" ++ pretty f 1 ++ " " ++ pretty t 0 ++ ")"+ +instance Pretty FTFn where+ pretty Tr _ = "Tr"+ pretty Tr' _ = "Tr'"+ +instance (Pretty a) => Pretty (Qual a) where+ pretty (ps :=> t) _ = (mapIntersperseConcat (flip pretty 1) ", " ps) ++ " => " ++ pretty t 1 + +instance Pretty Pred where+ pretty (IsIn s t) _ = s ++ " " ++ pretty t 1+ pretty (Has r f t) _ = pretty r 1 ++ " <: {" ++ pretty f 1 ++ " ::" ++ pretty t 1 ++ "}"++instance Pretty (RLabel, FType) where+ pretty (n, t) i = pretty n i ++ " :: " ++ pretty t i++instance Pretty RLabel where+ pretty (RLabel n) _ = n+ pretty (RGen n) _ = "f" ++ show n+ pretty (RVar n) _ = "f" ++ show n +
+ src/Database/Ferry/TypedCore/Rewrite/Combinators.hs view
@@ -0,0 +1,75 @@+{- | Helper functions to construct a typed AST -}+{-# LANGUAGE TemplateHaskell #-}+module Database.Ferry.TypedCore.Rewrite.Combinators where++import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Data.Instances()+import Database.Ferry.Impossible++import qualified Data.List as L+ +-- | Count variable node, needs a specialized type in the AST and therefore still expects the type of the list+countF :: Qual FType -> CoreExpr+countF (q :=> t) = Var (q :=> t .-> int) "count" ++-- | Wrap an expression that is to be passed as an argument to a function+wrapArg :: CoreExpr -> Param+wrapArg e = ParExpr (typeOf e) e++-- | Apply equality operator to two expressions+eq :: CoreExpr -> CoreExpr -> CoreExpr+eq e1 e2 = BinOp ([] :=> FBool) (Op "==") e1 e2++-- | Apply negation to expression+notF :: CoreExpr -> CoreExpr+notF e = App ([] :=> FBool) (Var ([] :=> FBool .-> FBool) "not") (ParExpr (typeOf e) e) ++-- | Apply length function to expression+lengthF :: CoreExpr -> CoreExpr+lengthF e = let (q :=> t) = typeOf e+ in App ([] :=> FInt) (Var (q :=> t .-> FInt) "length") (ParExpr (typeOf e) e)++minPF :: CoreExpr -> CoreExpr -> CoreExpr+minPF e1 e2 = let (q1 :=> t1) = typeOf e1+ (q2 :=> t2) = typeOf e2+ fn' = Var (q1 `L.union` q2 :=> t1 .-> t2 .-> FInt) "minP"+ app1 = App (q2 :=> t2 .-> FInt) fn' (ParExpr (typeOf e1) e1)+ in App ([] :=> FInt) app1 (ParExpr (typeOf e2) e2)+ +-- | Create the zip variable node with specialized function type+zipF :: Qual FType -> Qual FType -> CoreExpr+zipF (q1 :=> FList t1) (q2 :=> FList t2) = Var ((q1 `L.union` q2) :=> FList t1 .-> FList t2 .-> (FList $ rec [(RLabel "1", t1), (RLabel "2", t2)])) "zip"+zipF _ _ = $impossible++-- | Create a typed let binding node +binding :: String -> CoreExpr -> CoreExpr -> CoreExpr+binding s e eb = Let (typeOf eb) s e eb++-- | Zip two list+zipC :: CoreExpr -> CoreExpr -> CoreExpr+zipC e1 e2 = let ty1 = typeOf e1+ ty2@(_ :=> t2) = typeOf e2+ zipV = zipF ty1 ty2+ (q :=> zipT) = zippedTy ty1 ty2 + app1T = q :=> t2 .-> zipT+ in App (q :=> zipT) (App app1T zipV (ParExpr ty1 e1)) (ParExpr ty2 e2)+ +-- | All variable node +allN :: CoreExpr+allN = Var ([] :=> list FBool .-> FBool) "all"++mapN :: Qual FType -> Qual FType -> CoreExpr+mapN (q1 :=> t1) (q2 :=> t2) = Var (q1 `L.union` q2 :=> t1 .-> t2 .-> list FBool) "map"++-- | Chain two boolean expression together in an and relation +andExpr :: CoreExpr -> CoreExpr -> CoreExpr+andExpr = BinOp ([] :=> FBool) (Op "&&")++orExpr :: CoreExpr -> CoreExpr -> CoreExpr+orExpr = BinOp ([] :=> FBool) (Op "||")++-- | Return the type that two lists that are zipped would result in+zippedTy :: Qual FType -> Qual FType -> Qual FType+zippedTy (q1 :=> (FList t1)) (q2 :=> (FList t2)) = (q1 `L.union` q2) :=> (FList $ rec [(RLabel "1", t1), (RLabel "2", t2)])+zippedTy _ _ = $impossible
+ src/Database/Ferry/TypedCore/Rewrite/OpRewrite.hs view
@@ -0,0 +1,175 @@+{-| Rewrite operators. +This means that operators on structures are expanded and applied to their individual components. -}+{-# LANGUAGE TemplateHaskell #-}+module Database.Ferry.TypedCore.Rewrite.OpRewrite where+ +import Database.Ferry.TypedCore.Data.Type+import Database.Ferry.TypedCore.Data.TypedCore+import Database.Ferry.TypedCore.Convert.Traverse+import Database.Ferry.TypedCore.Data.Instances()+import Database.Ferry.TypedCore.Rewrite.Combinators++import Database.Ferry.Impossible++import Control.Monad.State++type Rewrite = State Int++getFreshIdentifier :: Rewrite String+getFreshIdentifier = do+ n <- get+ put $ n + 1+ return $ "_rw" ++ show n++getFreshVar :: Rewrite (Qual FType -> CoreExpr)+getFreshVar = do+ i <- getFreshIdentifier+ return (\t -> Var t i)+ +runRewrite :: Rewrite a -> a+runRewrite i = fst $ runState i 1+ +rewrite :: CoreExpr -> CoreExpr+rewrite = runRewrite . rewrite' ++rewrite' :: CoreExpr -> Rewrite CoreExpr+rewrite' = traverse rules+ where+ rules = mFoldCore {binOpF = opRewrite, appF = appRewrite}++appRewrite :: Qual FType -> Rewrite CoreExpr -> Rewrite Param -> Rewrite CoreExpr+appRewrite qt e arg = do+ e' <- e+ arg' <- arg+ case (e', arg') of+ (App _ (Var _ "concatMap") f, e2) -> return $ concatMapR qt f e2+ (Var _ "fst", ParExpr _ e2) -> return $ Elem qt e2 "1"+ (Var _ "snd", ParExpr _ e2) -> return $ Elem qt e2 "2"+ _ -> return $ App qt e' arg'++opRewrite :: Qual FType -> Op -> Rewrite CoreExpr -> Rewrite CoreExpr -> Rewrite CoreExpr+opRewrite qt (Op op) e1 e2 = do+ e1' <- e1+ e2' <- e2+ v1 <- getFreshIdentifier+ v2 <- getFreshIdentifier+ let (_ :=> ty1) = typeOf e1'+ case (ty1, op) of+ (FList _t, "==") -> liftM (addBindings v1 v2 e1' e2') $ eqListExpr v1 v2 e1' e2'+ (FRec _t, "==") -> liftM (addBindings v1 v2 e1' e2') $ eqRecExpr v1 v2 e1' e2'+ (_ty, "!=") -> liftM (addBindings v1 v2 e1' e2') $ notEq e1' e2'+ (FList _t, "<") -> liftM (addBindings v1 v2 e1' e2') $ ordList v1 v2 e1' e2' + (FRec _t, "<") -> liftM (addBindings v1 v2 e1' e2') $ ordRec "<" v1 v2 e1' e2'+ (FList _t, ">") -> liftM (addBindings v1 v2 e1' e2') $ ordList v2 v1 e2' e1' + (FRec _t, ">") -> liftM (addBindings v1 v2 e1' e2') $ ordRec ">" v1 v2 e1' e2'+ (_t, "<=") -> liftM (addBindings v1 v2 e1' e2') $ opOrEq "<" v1 v2 e1' e2'+ (_t, ">=") -> liftM (addBindings v1 v2 e1' e2') $ opOrEq ">" v1 v2 e1' e2'+ (_t, o) -> return $ BinOp qt (Op o) e1' e2'++concatMapR :: Qual FType -> Param -> Param -> CoreExpr+concatMapR qt@(q :=> rt) f e = let (_ :=> mft) = typeOf f+ (_ :=> lt) = typeOf e+ in App qt (Var (q :=> (list rt .-> rt)) "concat")+ (ParExpr (q :=> list rt) (App (q :=> rt) + (App (q :=> (lt .-> rt)) (Var (q :=> (mft .-> lt .-> rt)) "map") f) e))++addBindings :: String -> String -> CoreExpr -> CoreExpr -> CoreExpr -> CoreExpr+addBindings v1 v2 val1 val2 val3 = Let ([] :=> FBool) v1 val1 + $ Let ([] :=> FBool) v2 val2 val3+ ++opOrEq :: String -> String -> String -> CoreExpr -> CoreExpr -> Rewrite CoreExpr+opOrEq op id1 id2 v1 v2 = let var1 = Var (typeOf v1) id1+ var2 = Var (typeOf v2) id2+ in rewrite' $ BinOp ([] :=> FBool) (Op "||") + (BinOp ([] :=> FBool) (Op op) var1 var2) + (BinOp ([] :=> FBool) (Op "==") var1 var2)++ordRec :: String -> String -> String -> CoreExpr -> CoreExpr -> Rewrite CoreExpr+ordRec op id1 id2 v1 v2 = let (q :=> FRec ls) = typeOf v1+ var1 = Var (typeOf v1) id1+ var2 = Var (typeOf v2) id2+ els = [(Elem (q :=> t) var1 l, Elem (q :=> t) var2 l) | (RLabel l, t) <- ls]+ in rewrite' $ recCompExpr op els++recCompExpr :: String -> [(CoreExpr, CoreExpr)] -> CoreExpr+recCompExpr op [(v1, v2)] = BinOp ([] :=> FBool) (Op op) v1 v2+recCompExpr op ((v1, v2):vs) = let opE = BinOp ([] :=> FBool) (Op op) v1 v2+ eqE = BinOp ([] :=> FBool) (Op "==") v1 v2+ in BinOp ([] :=> FBool) (Op "||") opE + $ BinOp ([] :=> FBool) (Op "&&") eqE + $ recCompExpr op vs+recCompExpr _ [] = $impossible++ordList :: String -> String -> CoreExpr -> CoreExpr -> Rewrite CoreExpr+ordList id1 id2 val1 val2 = let t1@(_ :=> (FList _)) = typeOf val1+ t2@(_ :=> (FList _)) = typeOf val2+ var1 = Var t1 id1+ var2 = Var t2 id2+ lens = BinOp ([] :=> FBool) (Op "<") (lengthF var1) (lengthF var2)+ eqMinPf = (minPF var1 var2) `eq` (minPF var2 var1)+ ltMinPf = BinOp ([] :=> FBool) (Op "<") (minPF var1 var2) $ minPF var2 var1+ in rewrite' $ flip orExpr ltMinPf $ andExpr lens eqMinPf+ +eqRecExpr :: String -> String -> CoreExpr -> CoreExpr -> Rewrite CoreExpr+eqRecExpr id1 id2 val1 val2 = do+ let t1@(q1 :=> (FRec ls1)) = typeOf val1+ let t2@(_ :=> (FRec _)) = typeOf val2+ let var1 = Var t1 id1+ let var2 = Var t2 id2+ let eqs = [recElemEq l (q1 :=> ty) var1 var2 | (RLabel l, ty) <- ls1]+ eqs' <- sequence $ map rewrite' eqs+ return $ foldl1 andExpr eqs'+ +recElemEq :: String -> Qual FType -> CoreExpr -> CoreExpr -> CoreExpr+recElemEq lab (q :=> t) v1 v2 = let el1 = Elem (q :=> t) v1 lab+ el2 = Elem (q :=> t) v2 lab+ in el1 `eq` el2+ + + +-- | Rewrite of list equality+eqListExpr :: String -> String -> CoreExpr -> CoreExpr -> Rewrite CoreExpr+eqListExpr id1 id2 val1 val2 = do+ let t1 = typeOf val1+ let t2 = typeOf val2+ let var1 = Var t1 id1+ let var2 = Var t2 id2+ elEq <- elemEq var1 var2+ return $ andExpr (eqLength var1 var2) elEq+ +-- | Given two list expressions returns an expression that checks that they have equal length+eqLength :: CoreExpr -> CoreExpr -> CoreExpr+eqLength e1 e2 = let (q1 :=> t1) = typeOf e1+ (q2 :=> t2) = typeOf e2+ count1 = App ([] :=> FInt) (countF (q1 :=> t1 .-> FInt)) $ wrapArg e1+ count2 = App ([] :=> FInt) (countF (q2 :=> t2 .-> FInt)) $ wrapArg e2+ in BinOp ([] :=> FBool) (Op "==") count1 count2++-- | Given two lists of equal length compute elementwise equality+elemEq :: CoreExpr -> CoreExpr -> Rewrite CoreExpr+elemEq e1 e2 = do+ let t1 = typeOf e1+ let t2 = typeOf e2+ let zipE = zipC e1 e2+ eqA <- eqAbstr t1 t2+ let (qE :=> tE) = typeOf zipE+ let mapNode = mapN (typeOf eqA) (qE :=> tE)+ let app1 = App (qE :=> tE .-> list FBool) mapNode eqA+ let app2 = App ([] :=> list FBool) app1 (ParExpr (qE :=> tE) zipE)+ return $ App ([] :=> FBool) allN (ParExpr (typeOf app2) app2) ++eqAbstr :: Qual FType -> Qual FType -> Rewrite Param+eqAbstr ty1@(q1 :=> FList t1) ty2@(q2 :=> FList t2) = + do+ f <- getFreshIdentifier+ let ty@(q :=> t) = zippedTy ty1 ty2+ let fV = Var ty f+ let el1 = Elem (q1 :=> t1) fV "1"+ let el2 = Elem (q2 :=> t2) fV "2"+ eqE <- rewrite' $ BinOp ([] :=> FBool) (Op "==") el1 el2+ return $ ParAbstr (q :=> t .-> FBool) [f] eqE +eqAbstr _ _ = $impossible++notEq :: CoreExpr -> CoreExpr -> Rewrite CoreExpr+notEq e1 e2 = rewrite' $ notF (BinOp ([] :=> FBool) (Op "==") e1 e2)