packages feed

DSH 0.7.8.2 → 0.8.0.1

raw patch · 18 files changed

+1757/−2233 lines, 18 filesdep −convertibledep −jsondep −sybdep ~FerryCoredep ~HDBCdep ~HaXmlPVP ok

version bump matches the API change (PVP)

Dependencies removed: convertible, json, syb, xhtml

Dependency ranges changed: FerryCore, HDBC, HaXml, Pathfinder, array, base, bytestring, containers, csv, mtl, template-haskell, text

API changes (from Hackage documentation)

- Database.DSH: (><) :: QA a => Q [a] -> Q [a] -> Q [a]
- Database.DSH: class BasicType a
- Database.DSH: class QA a => TA a where tablePersistence t = Q (TableE t (reify (undefined :: [a])))
- Database.DSH: csvExport :: QA a => FilePath -> [a] -> IO ()
- Database.DSH: csvExportHandle :: QA a => Handle -> [a] -> IO ()
- Database.DSH: csvExportStdout :: QA a => [a] -> IO ()
- Database.DSH: csvImport :: FilePath -> Type -> IO Norm
- Database.DSH: generateDatabaseRecordInstances :: IConnection conn => (IO conn) -> Q [Dec]
- Database.DSH: generateRecordInstances :: Q [Dec] -> Q [Dec]
- Database.DSH: generateTableDeclarations :: IConnection conn => (IO conn) -> Q [Dec]
- Database.DSH: generateTableRecordInstances :: IConnection conn => (IO conn) -> String -> String -> [Name] -> Q [Dec]
- Database.DSH: jsonExport :: QA a => FilePath -> [a] -> IO ()
- Database.DSH: jsonExportHandle :: QA a => Handle -> [a] -> IO ()
- Database.DSH: jsonExportStdout :: QA a => [a] -> IO ()
- Database.DSH: xhtmlExport :: QA a => FilePath -> [a] -> IO ()
- Database.DSH: xhtmlExportHandle :: QA a => Handle -> [a] -> IO ()
- Database.DSH: xhtmlExportStdout :: QA a => [a] -> IO ()
+ Database.DSH: (++) :: QA a => Q [a] -> Q [a] -> Q [a]
+ Database.DSH: class (QA a, QA r) => Elim a r
+ Database.DSH: eitherToPair :: (QA a, QA b) => Q (Either a b) -> Q ([a], [b])
+ Database.DSH: elim :: Elim a r => Q a -> Eliminator a r
+ Database.DSH: pair :: (QA a, QA b) => Q a -> Q b -> Q (a, b)
+ Database.DSH: pairToEither :: (QA a, QA b) => Q ([a], [b]) -> Q (Either a b)
+ Database.DSH.Compiler: debugCoreDot :: (IConnection conn, Reify a) => conn -> Exp a -> IO String
- Database.DSH: (/=) :: (Eq a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: (/=) :: (QA a, Eq a) => Q a -> Q a -> Q Bool
- Database.DSH: (<) :: (Ord a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: (<) :: (QA a, Ord a) => Q a -> Q a -> Q Bool
- Database.DSH: (<=) :: (Ord a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: (<=) :: (QA a, Ord a) => Q a -> Q a -> Q Bool
- Database.DSH: (==) :: (Eq a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: (==) :: (QA a, Eq a) => Q a -> Q a -> Q Bool
- Database.DSH: (>) :: (Ord a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: (>) :: (QA a, Ord a) => Q a -> Q a -> Q Bool
- Database.DSH: (>=) :: (Ord a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: (>=) :: (QA a, Ord a) => Q a -> Q a -> Q Bool
- Database.DSH: class QA a
+ Database.DSH: class Reify (Rep a) => QA a
- Database.DSH: class View a b | a -> b, b -> a
+ Database.DSH: class (ToView a ~ b, FromView b ~ a) => View a b
- Database.DSH: elem :: (Eq a, QA a) => Q a -> Q [a] -> Q Bool
+ Database.DSH: elem :: (QA a, Eq a) => Q a -> Q [a] -> Q Bool
- Database.DSH: eq :: (Eq a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: eq :: (QA a, Eq a) => Q a -> Q a -> Q Bool
- Database.DSH: groupWith :: (Ord b, QA a, QA b) => (Q a -> Q b) -> Q [a] -> Q [[a]]
+ Database.DSH: groupWith :: (QA a, QA b, Ord b) => (Q a -> Q b) -> Q [a] -> Q [[a]]
- Database.DSH: gt :: (Ord a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: gt :: (QA a, Ord a) => Q a -> Q a -> Q Bool
- Database.DSH: gte :: (Ord a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: gte :: (QA a, Ord a) => Q a -> Q a -> Q Bool
- Database.DSH: lt :: (Ord a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: lt :: (QA a, Ord a) => Q a -> Q a -> Q Bool
- Database.DSH: lte :: (Ord a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: lte :: (QA a, Ord a) => Q a -> Q a -> Q Bool
- Database.DSH: max :: (Ord a, QA a) => Q a -> Q a -> Q a
+ Database.DSH: max :: (QA a, Ord a) => Q a -> Q a -> Q a
- Database.DSH: min :: (Ord a, QA a) => Q a -> Q a -> Q a
+ Database.DSH: min :: (QA a, Ord a) => Q a -> Q a -> Q a
- Database.DSH: neq :: (Eq a, QA a) => Q a -> Q a -> Q Bool
+ Database.DSH: neq :: (QA a, Eq a) => Q a -> Q a -> Q Bool
- Database.DSH: notElem :: (Eq a, QA a) => Q a -> Q [a] -> Q Bool
+ Database.DSH: notElem :: (QA a, Eq a) => Q a -> Q [a] -> Q Bool
- Database.DSH: nub :: (Eq a, QA a) => Q [a] -> Q [a]
+ Database.DSH: nub :: (QA a, Eq a) => Q [a] -> Q [a]
- Database.DSH: sortWith :: (Ord b, QA a, QA b) => (Q a -> Q b) -> Q [a] -> Q [a]
+ Database.DSH: sortWith :: (QA a, QA b, Ord b) => (Q a -> Q b) -> Q [a] -> Q [a]
- Database.DSH: table :: TA a => String -> Q [a]
+ Database.DSH: table :: (QA a, TA a) => String -> Q [a]
- Database.DSH: tableCSV :: TA a => String -> Q [a]
+ Database.DSH: tableCSV :: (QA a, TA a) => String -> Q [a]
- Database.DSH: tableDB :: TA a => String -> Q [a]
+ Database.DSH: tableDB :: (QA a, TA a) => String -> Q [a]
- Database.DSH: tableWithKeys :: TA a => String -> [[String]] -> Q [a]
+ Database.DSH: tableWithKeys :: (QA a, TA a) => String -> [[String]] -> Q [a]
- Database.DSH: the :: (Eq a, QA a) => Q [a] -> Q a
+ Database.DSH: the :: (QA a, Eq a) => Q [a] -> Q a
- Database.DSH.Compiler: debugCore :: (QA a, IConnection conn) => conn -> Q a -> IO String
+ Database.DSH.Compiler: debugCore :: (IConnection conn, Reify a) => conn -> Exp a -> IO String
- Database.DSH.Compiler: debugPlan :: (QA a, IConnection conn) => conn -> Q a -> IO String
+ Database.DSH.Compiler: debugPlan :: (IConnection conn, Reify a) => conn -> Exp a -> IO String
- Database.DSH.Compiler: debugPlanOpt :: (QA a, IConnection conn) => conn -> Q a -> IO String
+ Database.DSH.Compiler: debugPlanOpt :: (IConnection conn, Reify a) => conn -> Exp a -> IO String
- Database.DSH.Compiler: debugSQL :: (QA a, IConnection conn) => conn -> Q a -> IO String
+ Database.DSH.Compiler: debugSQL :: (IConnection conn, Reify a) => conn -> Exp a -> IO String

Files

DSH.cabal view
@@ -1,5 +1,5 @@ Name:                DSH-Version:             0.7.8.2+Version:             0.8.0.1 Synopsis:            Database Supported Haskell Description:   This is a Haskell library for database-supported program execution. Using@@ -32,6 +32,9 @@   reading. The package includes a couple of examples that demonstrate how to   use DSH.   .+  This is a highly experimental realise supporting our work-in-progress paper on+  "Algebraic Data Types for Language-Integrated Queries".+  .   1. <http://db.inf.uni-tuebingen.de/files/giorgidze/ifl2010.pdf>  License:             BSD3@@ -43,44 +46,45 @@ Build-type:          Simple  Extra-source-files:  examples/Example01.hs-                     examples/Example02.hs                      examples/Makefile                      tests/Main.hs                      tests/Makefile -Cabal-version:       >= 1.2+Cabal-version:       >= 1.4  Library-  Build-depends:     base               >= 4.3.1.0 && < 5,-                     containers         >= 0.4.0.0,-                     array              >= 0.3.0.2,-                     syb                >= 0.3,-                     mtl                >= 2.0.1.0,-                     bytestring         >= 0.9.1.10,-                     text               >= 0.11.0.6,-                     HDBC               >= 2.3.1.0,-                     convertible        >= 1.0.11.0,-                     template-haskell   >= 2.5.0.0,-                     HaXml              >= 1.22.5,-                     csv                >= 0.1.2,-                     json               >= 0.5,-                     xhtml              >= 3000.2.0.1,-                     Pathfinder         >= 0.5.10,-                     FerryCore          >= 0.4.6.4+  Extensions:        TemplateHaskell,+                     ScopedTypeVariables,+                     FlexibleContexts,+                     FlexibleInstances,+                     MultiParamTypeClasses,+                     TypeFamilies,+                     GADTs +  Build-depends:     base               >= 4.5 && < 5,+                     containers         >= 0.4,+                     array              >= 0.4,+                     bytestring         >= 0.9,+                     template-haskell   >= 2.7,+                     mtl                >= 2.1,+                     text               >= 0.11,+                     HDBC               >= 2.3,+                     HaXml              >= 1.23,+                     csv                >= 0.1,+                     Pathfinder         >= 0.5,+                     FerryCore          >= 0.4+   Hs-source-dirs:    src -  GHC-options:       -O3 -Wall+  GHC-options:       -O3 -Wall -fno-warn-orphans -  Exposed-modules:   Database.DSH-                     Database.DSH.Interpreter+  Exposed-modules:   Database.DSH.Interpreter                      Database.DSH.Compiler+                     Database.DSH -  Other-modules:     Database.DSH.TH-                     Database.DSH.Data-                     Database.DSH.Combinators+  Other-modules:     Database.DSH.Internals+                     Database.DSH.Externals                      Database.DSH.CSV-                     Database.DSH.JSON-                     Database.DSH.XHTML                      Database.DSH.Impossible                      Database.DSH.Compile+                     Database.DSH.TH
− examples/Example02.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE TemplateHaskell, FlexibleInstances, MultiParamTypeClasses #-}--module Main where--import qualified Prelude as P-import Database.DSH--import Database.HDBC.PostgreSQL-          -$(generateDatabaseRecordInstances (connectPostgreSQL "user = 'giorgidz' password = '' host = 'localhost' dbname = 'giorgidz'"))-$(generateTableDeclarations       (connectPostgreSQL "user = 'giorgidz' password = '' host = 'localhost' dbname = 'giorgidz'"))--main :: IO ()-main = P.return ()
examples/Makefile view
@@ -1,7 +1,6 @@ all: clean 		ghc -Wall -O3 --make Example01.hs-		ghc -Wall -O3 --make Example02.hs 		rm -rf *.hi *.o  clean:-		rm -rf *.hi *.o Example01 Example02+		rm -rf *.hi *.o Example01
src/Database/DSH.hs view
@@ -14,27 +14,8 @@ -- by Database.DSH.  module Database.DSH-  (-    module Database.DSH.Combinators--    -- * Data Types-  , Q--    -- * Type Classes-  , QA-  , TA, table, tableDB, tableCSV, tableWithKeys, BasicType-  , View, view, fromView, tuple, record--    -- * Template Haskell: Creating Table Representations-  , generateDatabaseRecordInstances-  , generateTableRecordInstances-  , generateRecordInstances-  , generateTableDeclarations--  , module Database.DSH.CSV-  , module Database.DSH.JSON-  , module Database.DSH.XHTML-+  ( module Database.DSH.Externals+  , Q, QA, Elim, elim, View, view, fromView   , module Data.String   , module Data.Text   , module Database.HDBC@@ -42,19 +23,12 @@   )   where -import Database.DSH.Data (Q, QA, TA, table, tableDB, tableCSV, tableWithKeys, BasicType, View, view, fromView, tuple, record)-import Database.DSH.TH (generateDatabaseRecordInstances, generateTableRecordInstances, generateRecordInstances, generateTableDeclarations)--import Database.DSH.CSV-import Database.DSH.JSON-import Database.DSH.XHTML--import Database.DSH.Combinators+import Database.DSH.Externals+import Database.DSH.Internals (Q,QA,Elim,elim,View,view,fromView) -import Data.String(IsString,fromString)+import Data.String (IsString,fromString) import Data.Text (Text) import Database.HDBC- import Prelude hiding (     not   , (&&)@@ -78,6 +52,7 @@   , null   , length   , (!!)+  , (++)   , reverse   , and   , or
src/Database/DSH/CSV.hs view
@@ -1,83 +1,39 @@-{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}--module Database.DSH.CSV (csvImport, csvExport, csvExportHandle, csvExportStdout) where+module Database.DSH.CSV (csvImport) where -import Database.DSH.Data-import Database.DSH.Impossible+import Database.DSH.Internals -import Text.CSV-import Data.Text (Text) import qualified Data.Text as T-import qualified Data.Text.IO as T--import qualified System.IO as IO-import System.IO (Handle)--csvExport :: (QA a) => FilePath -> [a] -> IO ()-csvExport file as = IO.withFile file IO.WriteMode (\handle -> csvExportHandle handle as)--csvExportStdout :: (QA a) => [a] -> IO ()-csvExportStdout = csvExportHandle IO.stdout--csvExportHandle :: (QA a) => Handle -> [a] -> IO ()-csvExportHandle handle as = T.hPutStr handle csvContent-  where csvContent :: Text-        csvContent = T.unlines (map (toRow . toNorm) as)--        quote :: Text -> Text-        quote s = T.concat ["\"",s,"\""]-        -        escape :: Text -> Text-        escape = (T.replace "\t" "\\t") .-                 (T.replace "\r" "\\r") .-                 (T.replace "\n" "\\n") .-                 (T.replace "\"" "\"\"")--        toRow :: Norm -> Text-        toRow e = case e of-                    ListN _ _       -> "Nesting"-                    UnitN _         -> quote "()"-                    BoolN b _       -> quote (T.pack (show b))-                    CharN c _       -> quote (escape (T.singleton c))-                    IntegerN i _    -> quote (T.pack (show i))-                    DoubleN d _     -> quote (T.pack (show d))-                    TextN t _       -> quote (escape t)-                    TupleN e1 e2 _  -> T.concat [toRow e1,",",toRow e2]-+import Text.CSV -csvImport :: FilePath -> Type -> IO Norm+csvImport :: (Reify a) => FilePath -> Type [a] -> IO (Exp [a]) csvImport filepath csvType = do   let rType = recordType csvType   contents <- readFile filepath   let csv1 = case parseCSV filepath contents of                Left er -> error (show er)                Right r -> filter (\l -> not (all null l) || length l > 1) (tail r)-  return (ListN (fmap (csvRecordToNorm rType) csv1) (ListT rType))+  return (ListE (fmap (csvRecordToNorm rType) csv1))   where csvError :: String -> a         csvError s = error ("Error in '" ++ filepath ++ "': " ++ s) -        recordType :: Type -> Type+        recordType :: Type [a] -> Type a         recordType (ListT rType) = rType-        recordType _ = $impossible -        csvRecordToNorm :: Type -> [String] -> Norm-        csvRecordToNorm t rs = case (t,rs) of-          (UnitT       , []      ) -> UnitN UnitT-          (_           , []      ) -> er-          (t1          , [bs]    ) -> csvFieldToNorm t1 bs-          (TupleT t1 t2, bs : bss) -> TupleN (csvFieldToNorm t1 bs) (csvRecordToNorm t2 bss) (TupleT t1 t2)-          (_           , _       ) -> er-          where er = csvError ("When converting record '" ++ show rs ++ "' to a value of type '" ++ show t ++ "'")+        csvRecordToNorm :: Type a -> [String] -> Exp a+        csvRecordToNorm UnitT  [] = UnitE+        csvRecordToNorm t      [] = csvError ("When converting record '" ++ "[]" ++ "' to a value of type '" ++ show t ++ "'")+        csvRecordToNorm t1     [bs] = csvFieldToNorm t1 bs+        csvRecordToNorm (PairT (t1 :: Type b) (t2 :: Type c)) (bs : bss) = PairE (csvFieldToNorm t1 bs :: Exp b) (csvRecordToNorm t2 bss)+        csvRecordToNorm t           rs       = csvError ("When converting record '" ++ show rs ++ "' to a value of type '" ++ show t ++ "'") -        csvFieldToNorm :: Type -> String -> Norm++        csvFieldToNorm :: Type a -> String -> Exp a         csvFieldToNorm t s = case t of-          UnitT      -> UnitN             UnitT-          BoolT      -> BoolN    (read s) BoolT-          CharT      -> CharN    (head s) CharT-          IntegerT   -> IntegerN (read s) IntegerT-          DoubleT    -> DoubleN  (read s) DoubleT-          TextT      -> TextN    (T.pack s) TextT-          TupleT _ _ -> er-          ListT _    -> er-          ArrowT _ _ -> er+          UnitT      -> UnitE+          BoolT      -> BoolE    (read s) +          CharT      -> CharE    (head s) +          IntegerT   -> IntegerE (read s) +          DoubleT    -> DoubleE  (read s) +          TextT      -> TextE    (T.pack s) +          _          -> er           where er = csvError ("When converting CSV field'" ++ s ++ "' to a value of type '" ++ show t ++ "'")
− src/Database/DSH/Combinators.hs
@@ -1,398 +0,0 @@-{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, MultiParamTypeClasses, FlexibleInstances #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Database.DSH.Combinators where--import Database.DSH.Data-import Database.DSH.TH--import Data.Convertible--import Prelude (Eq, Ord, Num, Bool(..), Integer, Double, Maybe, Either, undefined, error, ($), (.))---- * Unit--unit :: Q ()-unit = Q (UnitE $ reify (undefined :: ()))---- * Boolean logic--false :: Q Bool-false = Q (BoolE False BoolT)--true :: Q Bool-true = Q (BoolE True BoolT)--not :: Q Bool -> Q Bool-not (Q b) = Q (AppE1 Not b $ reify (undefined :: Bool))--(&&) :: Q Bool -> Q Bool -> Q Bool-(&&) (Q a) (Q b) = Q (AppE2 Conj a b $ reify (undefined :: Bool))--(||) :: Q Bool -> Q Bool -> Q Bool-(||) (Q a) (Q b) = Q (AppE2 Disj a b $ reify (undefined :: Bool))---- * Equality and Ordering--eq :: (Eq a,QA a) => Q a -> Q a -> Q Bool-eq (Q a) (Q b) = Q (AppE2 Equ a b $ reify (undefined :: Bool))--(==) :: (Eq a,QA a) => Q a -> Q a -> Q Bool-(==) = eq--neq :: (Eq a,QA a) => Q a -> Q a -> Q Bool-neq a b = not (eq a b)--(/=) :: (Eq a,QA a) => Q a -> Q a -> Q Bool-(/=) = neq--lt :: (Ord a,QA a) => Q a -> Q a -> Q Bool-lt (Q a) (Q b) = Q (AppE2 Lt a b $ reify (undefined :: Bool))--(<) :: (Ord a,QA a) => Q a -> Q a -> Q Bool-(<) = lt--lte :: (Ord a,QA a) => Q a -> Q a -> Q Bool-lte (Q a) (Q b) = Q (AppE2 Lte a b $ reify (undefined :: Bool))--(<=) :: (Ord a,QA a) => Q a -> Q a -> Q Bool-(<=) = lte--gte :: (Ord a,QA a) => Q a -> Q a -> Q Bool-gte (Q a) (Q b) = Q (AppE2 Gte a b $ reify (undefined :: Bool))--(>=) :: (Ord a,QA a) => Q a -> Q a -> Q Bool-(>=) = gte--gt :: (Ord a,QA a) => Q a -> Q a -> Q Bool-gt (Q a) (Q b) = Q (AppE2 Gt a b $ reify (undefined :: Bool))--(>) :: (Ord a,QA a) => Q a -> Q a -> Q Bool-(>) = gt--min :: forall a. (Ord a, QA a) => Q a -> Q a -> Q a-min (Q a) (Q b) = Q (AppE2 Min a b $ reify (undefined :: a))--max :: forall a. (Ord a, QA a) => Q a -> Q a -> Q a-max (Q a) (Q b) = Q (AppE2 Max a b $ reify (undefined :: a))----- * Conditionals--- | Boolean fold--- | It's first argument is used in the case of False--- | It's second argument is used in the case of True--- | The third argument is the boolean-bool :: (QA a) => Q a -> Q a -> Q Bool -> Q a-bool f t b = cond b t f--cond :: forall a. (QA a) => Q Bool -> Q a -> Q a -> Q a-cond (Q c) (Q a) (Q b) = Q (AppE3 Cond c a b $ reify (undefined :: a))--(?) :: (QA a) => Q Bool -> (Q a,Q a) -> Q a-(?) c (a,b) = cond c a b---- * Maybe--listToMaybe :: QA a => Q [a] -> Q (Maybe a)-listToMaybe (Q as) = (Q as)--maybeToList :: QA a => Q (Maybe a) -> Q [a]-maybeToList (Q ma) = (Q ma)--nothing :: QA a => Q (Maybe a)-nothing = listToMaybe nil--just :: QA a => Q a -> Q (Maybe a)-just a = listToMaybe (singleton a)--isNothing :: QA a => Q (Maybe a) -> Q Bool-isNothing ma = null (maybeToList ma)--isJust :: QA a => Q (Maybe a) -> Q Bool-isJust ma = not (isNothing ma)--fromJust :: QA a => Q (Maybe a) -> Q a-fromJust ma = head (maybeToList ma)--maybe :: (QA a, QA b) => Q b -> (Q a -> Q b) -> Q (Maybe a) -> Q b-maybe b f ma = (isNothing ma) ? (b, f (fromJust (ma)))--fromMaybe :: QA a => Q a -> Q (Maybe a) -> Q a-fromMaybe a ma = (isNothing ma) ? (a, fromJust (ma))--catMaybes :: QA a => Q [Maybe a] -> Q [a]-catMaybes mas = concatMap maybeToList mas--mapMaybe :: (QA a, QA b) => (Q a -> Q (Maybe b)) -> Q [a] -> Q [b]-mapMaybe f as = concatMap (maybeToList . f) as---- * Either--left :: (QA a,QA b) => Q a -> Q (Either a b)-left a = tupleToEither (tuple ((singleton a),nil))--right :: (QA a,QA b) => Q b -> Q (Either a b)-right a = tupleToEither (tuple (nil,(singleton a)))--isLeft :: (QA a,QA b) => Q (Either a b) -> Q Bool-isLeft = null . snd . eitherToTuple--isRight :: (QA a,QA b) => Q (Either a b) -> Q Bool-isRight = null . fst . eitherToTuple--either :: (QA a,QA b,QA c) => (Q a -> Q c) -> (Q b -> Q c) -> Q (Either a b) -> Q c-either lf rf e = (isLeft e) ? ((lf . head . fst . eitherToTuple) e,(rf . head . snd . eitherToTuple) e)--lefts :: (QA a,QA b) => Q [Either a b] -> Q [a]-lefts = concatMap (fst . eitherToTuple)--rights :: (QA a,QA b) => Q [Either a b] -> Q [b]-rights = concatMap (snd . eitherToTuple)--partitionEithers :: (QA a,QA b) => Q [Either a b] -> Q ([a], [b])-partitionEithers es = tuple (lefts es,rights es)---- * List Construction--nil :: forall a. (QA a) => Q [a]-nil = Q (ListE [] $ reify (undefined :: [a]))--empty :: (QA a) => Q [a]-empty = nil--cons :: forall a. (QA a) => Q a -> Q [a] -> Q [a]-cons (Q a) (Q as) = Q (AppE2 Cons a as $ reify (undefined :: [a]))--(<|) :: (QA a) => Q a -> Q [a] -> Q [a]-(<|) = cons--snoc :: forall a. (QA a) => Q [a] -> Q a -> Q [a]-snoc (Q as) (Q a) = Q (AppE2 Snoc as a $ reify (undefined :: [a]))--(|>) :: (QA a) => Q [a] -> Q a -> Q [a]-(|>) = snoc--singleton :: (QA a) => Q a -> Q [a]-singleton a = cons a nil---- * List Operations--head :: forall a. (QA a) => Q [a] -> Q a-head (Q as) = Q (AppE1 Head as $ reify (undefined :: a))--tail :: forall a. (QA a) => Q [a] -> Q [a]-tail (Q as) = Q (AppE1 Tail as $ reify (undefined :: [a]))--take :: forall a. (QA a) => Q Integer -> Q [a] -> Q [a]-take (Q i) (Q as) = Q (AppE2 Take i as $ reify (undefined :: [a]))--drop :: forall a. (QA a) => Q Integer -> Q [a] -> Q [a]-drop (Q i) (Q as) = Q (AppE2 Drop i as $ reify (undefined :: [a]))--map :: forall a b. (QA a, QA b) => (Q a -> Q b) ->  Q [a] -> Q [b]-map f (Q as) = Q (AppE2 Map (toLam1 f) as $ reify (undefined :: [b]))--append :: forall a. (QA a) => Q [a] -> Q [a] -> Q [a]-append (Q as) (Q bs) = Q (AppE2 Append as bs $ reify (undefined :: [a]))--(><) :: (QA a) => Q [a] -> Q [a] -> Q [a]-(><) = append--filter :: forall a. (QA a) => (Q a -> Q Bool) -> Q [a] -> Q [a]-filter f (Q as) = Q (AppE2 Filter (toLam1 f) as $ reify (undefined :: [a]))--groupWith :: forall a b. (Ord b, QA a, QA b) => (Q a -> Q b) -> Q [a] -> Q [[a]]-groupWith f (Q as) = Q (AppE2 GroupWith (toLam1 f) as $ reify (undefined :: [[a]]))--sortWith :: forall a b. (Ord b, QA a, QA b) => (Q a -> Q b) -> Q [a] -> Q [a]-sortWith f (Q as) = Q (AppE2 SortWith (toLam1 f) as $ reify (undefined :: [a]))--the :: forall a. (Eq a, QA a) => Q [a] -> Q a-the (Q as) = Q (AppE1 The as $ reify (undefined :: a))--last :: forall a. (QA a) => Q [a] -> Q a-last (Q as) = Q (AppE1 Last as $ reify (undefined :: a))--init :: forall a. (QA a) => Q [a] -> Q [a]-init (Q as) = Q (AppE1 Init as $ reify (undefined :: [a]))--null :: (QA a) => Q [a] -> Q Bool-null (Q as) = Q (AppE1 Null as $ reify (undefined :: Bool))--length :: (QA a) => Q [a] -> Q Integer-length (Q as) = Q (AppE1 Length as $ reify (undefined :: Integer))--index :: forall a. (QA a) => Q [a] -> Q Integer -> Q a-index (Q as) (Q i) = Q (AppE2 Index as i $ reify (undefined :: a))--(!!) :: (QA a) => Q [a] -> Q Integer -> Q a-(!!) = index--reverse :: forall a. (QA a) => Q [a] -> Q [a]-reverse (Q as) = Q (AppE1 Reverse as $ reify (undefined :: [a]))----- * Special folds--and       :: Q [Bool] -> Q Bool-and (Q as) = Q (AppE1 And as $ reify (undefined :: Bool))--or        :: Q [Bool] -> Q Bool-or (Q as) = Q (AppE1 Or as $ reify (undefined :: Bool))--any       :: (QA a) => (Q a -> Q Bool) -> Q [a] -> Q Bool-any f (Q as) = Q (AppE2 Any (toLam1 f) as $ reify (undefined :: Bool))--all       :: (QA a) => (Q a -> Q Bool) -> Q [a] -> Q Bool-all f (Q as) = Q (AppE2 All (toLam1 f) as $ reify (undefined :: Bool))--sum       :: forall a. (QA a, Num a) => Q [a] -> Q a-sum (Q as) = Q (AppE1 Sum as $ reify (undefined :: a))--concat    :: forall a. (QA a) => Q [[a]] -> Q [a]-concat (Q as) = Q (AppE1 Concat as $ reify (undefined :: [a]))--concatMap :: (QA a, QA b) => (Q a -> Q [b]) -> Q [a] -> Q [b]-concatMap f as = concat (map f as)--maximum   :: forall a. (QA a, Ord a) => Q [a] -> Q a-maximum (Q as) = Q (AppE1 Maximum as $ reify (undefined :: a))--minimum   :: forall a. (QA a, Ord a) => Q [a] -> Q a-minimum (Q as) = Q (AppE1 Minimum as $ reify (undefined :: a))---- * Sublists--splitAt   :: forall a. (QA a) => Q Integer -> Q [a] -> Q ([a], [a])-splitAt (Q i) (Q as) = Q (AppE2 SplitAt i as $ reify (undefined :: ([a],[a])))--takeWhile :: forall a. (QA a) => (Q a -> Q Bool) -> Q [a] -> Q [a]-takeWhile f (Q as) = Q (AppE2 TakeWhile (toLam1 f) as $ reify (undefined :: [a]))--dropWhile :: forall a. (QA a) => (Q a -> Q Bool) -> Q [a] -> Q [a]-dropWhile f (Q as) = Q (AppE2 DropWhile (toLam1 f) as $ reify (undefined :: [a]))--span      :: forall a. (QA a) => (Q a -> Q Bool) -> Q [a] -> Q ([a],[a])-span f (Q as) = Q (AppE2 Span (toLam1 f) as $ reify (undefined :: ([a],[a])))--break     :: forall a. (QA a) => (Q a -> Q Bool) -> Q [a] -> Q ([a],[a])-break f (Q as) = Q (AppE2 Break (toLam1 f) as $ reify (undefined :: ([a],[a])))----- * Searching Lists--elem :: forall a. (Eq a, QA a) => Q a -> Q [a] -> Q Bool-elem a as = (null (filter (a ==) as)) ? (false,true)--notElem :: forall a. (Eq a, QA a) => Q a -> Q [a] -> Q Bool-notElem a as = not (elem a as)--lookup :: (QA a,QA b,Eq a) => Q a -> Q [(a, b)] -> Q (Maybe b)-lookup a  = listToMaybe . map snd . filter ((a ==) . fst)---- * Zipping and Unzipping Lists--zip       :: forall a b. (QA a, QA b) => Q [a] -> Q [b] -> Q [(a,b)]-zip (Q as) (Q bs) = Q (AppE2 Zip as bs $ reify (undefined :: [(a,b)]))--zipWith   :: forall a b c. (QA a, QA b, QA c) => (Q a -> Q b -> Q c) -> Q [a] -> Q [b] -> Q [c]-zipWith f (Q as) (Q bs) = Q (AppE3 ZipWith (toLam2 f) as bs $ reify (undefined :: [c]))--unzip     :: forall a b. (QA a, QA b) => Q [(a,b)] -> Q ([a], [b])-unzip (Q as) = Q (AppE1 Unzip as  $ reify (undefined :: ([a],[b])))---- * "Set" operations--nub :: forall a. (Eq a,QA a) => Q [a] -> Q [a]-nub (Q as) = Q (AppE1 Nub as $ reify (undefined :: [a]))----- * Tuple Projection Functions--fst :: forall a b. (QA a, QA b) => Q (a,b) -> Q a-fst (Q a) = Q (AppE1 Fst a $ reify (undefined :: a))--snd :: forall a b. (QA a, QA b) => Q (a,b) -> Q b-snd (Q a) = Q (AppE1 Snd a $ reify (undefined :: b))----- * Conversions between numeric types--integerToDouble :: Q Integer -> Q Double-integerToDouble (Q a) = Q (AppE1 IntegerToDouble a DoubleT)---- * Convert Haskell values into DB queries--toQ   :: forall a. (QA a) => a -> Q a-toQ c = Q (convert (toNorm c))---- * Rebind Monadic Combinators--return :: (QA a) => Q a -> Q [a]-return = singleton--(>>=) :: (QA a, QA b) => Q [a] -> (Q a -> Q [b]) -> Q [b]-(>>=) ma f = concatMap f ma--(>>) :: (QA a, QA b) => Q [a] -> Q [b] -> Q [b]-(>>) ma mb = concatMap (\_ -> mb) ma--mzip :: (QA a, QA b) => Q [a] -> Q [b] -> Q [(a,b)]-mzip = zip--guard :: Q Bool -> Q [()]-guard c = cond c (singleton unit) nil--infixl 9 !!-infixr 5 ><, <|, |>-infix  4  ==, /=, <, <=, >=, >-infixr 3  &&-infixr 2  ||-infix  0  ?---- 'QA', 'TA' and 'View' instances for tuples up to the defined length.--$(generateDeriveTupleQARange   3 60)-$(generateDeriveTupleTARange   3 16)-$(generateDeriveTupleViewRange 3 16)----- * Missing Combinators--- $missing--{- $missing--This module offers most of the functions on lists given in PreludeList for the-'Q' type. Missing functions are:--General folds:--> foldl-> foldl1-> scanl-> scanl1-> foldr-> foldr1-> scanr-> scanr1--Infinit lists:--> iterate-> repeat-> cycle--String functions:--> lines-> words-> unlines-> unwords--Zipping and unzipping lists:--> zip3-> zipWith3-> unzip3---}
src/Database/DSH/Compile.hs view
@@ -1,15 +1,16 @@-{-# LANGUAGE ScopedTypeVariables, TemplateHaskell, ParallelListComp #-} module Database.DSH.Compile where -import Database.DSH.Data-import Database.DSH.Impossible (impossible)+import Database.DSH.Internals+import Database.DSH.Impossible  import Database.Pathfinder  import qualified Data.Array as A import qualified Data.List as L-import Data.Maybe (fromJust, isNothing, isJust)+import Data.Maybe (fromJust, isNothing, isJust, fromMaybe) import Data.List (sortBy)+import Data.Function+import Control.Arrow import Control.Monad.Reader import Control.Exception (evaluate) @@ -17,7 +18,8 @@ import Text.XML.HaXml (Content(..), AttValue(..), tag, deep, children, xmlParse, Document(..))  import Database.HDBC-import Data.Convertible+import qualified Data.Text as T+import qualified Data.Text.Encoding as T  -- | Wrapper type with phantom type for algebraic plan -- The type variable represents the type of the result of the plan@@ -48,7 +50,7 @@ -- | Translate the algebraic plan to SQL and then execute it using the provided  -- DB connection. If debug is switchd on the SQL code is written to a file  -- named query.sql-executePlan :: forall a. forall conn. (QA a, IConnection conn) => conn -> AlgebraXML a -> IO Norm+executePlan :: forall a. forall conn. (Reify a, IConnection conn) => conn -> AlgebraXML a -> IO (Exp a) executePlan c p = do                         sql@(SQL _s) <- algToSQL p                         runSQL c $ extractSQL sql@@ -75,28 +77,26 @@ extractSQL (SQL q) = let (Document _ _ r _) = xmlParse "query" q                       in Bundle $ map extractQuery $ (deep $ tag "query_plan") (CElem r $impossible)     where-        extractQuery c@(CElem (X.Elem n attrs cs) _) = let qId = case fmap attrToInt $ lookup (X.N "id") attrs of-                                                                    Just x -> x-                                                                    Nothing -> $impossible+        extractQuery c@(CElem (X.Elem n attrs cs) _) = let qId = maybe ($impossible) attrToInt (lookup (X.N "id") attrs)                                                            rId = fmap attrToInt $ lookup (X.N "idref") attrs                                                            cId = fmap attrToInt $ lookup (X.N "colref") attrs                                                            ref = liftM2 (,) rId cId                                                            query = extractCData $  head $ concatMap children $ deep (tag "query") c-                                                           schema = toSchemeInf $ map process $ concatMap (\x -> deep (tag "column") x) $ deep (tag "schema") c+                                                           schema = toSchemeInf $ map process $ concatMap (deep (tag "column")) $ deep (tag "schema") c                                                         in (qId, (query, schema, ref))         extractQuery _ = $impossible         attrToInt :: AttValue -> Int-        attrToInt (AttValue [(Left i)]) = read i+        attrToInt (AttValue [Left i]) = read i         attrToInt _ = $impossible         attrToString :: AttValue -> String-        attrToString (AttValue [(Left i)]) = i+        attrToString (AttValue [Left i]) = i         attrToString _ = $impossible         extractCData :: Content i -> String         extractCData (CString _ d _) = d         extractCData _ = $impossible         toSchemeInf :: [(String, Maybe Int)] -> SchemaInfo         toSchemeInf results = let iterName = fst $ head $ filter (\(_, p) -> isNothing p) results-                                  cols = map (\(n, v) -> (n, fromJust v)) $ filter (\(_, p) -> isJust p) results+                                  cols = map (second fromJust) $ filter (\(_, p) -> isJust p) results                                in SchemaInfo iterName cols         process :: Content i -> (String, Maybe Int)         process (CElem (X.Elem _ attrs _) _) = let name = fromJust $ fmap attrToString $ lookup (X.N "name") attrs@@ -105,15 +105,15 @@         process _ = $impossible  -- | Execute the given SQL queries and assemble the results into one structure-runSQL :: forall a. forall conn. (QA a, IConnection conn) => conn -> QueryBundle a -> IO Norm+runSQL :: forall a. forall conn. (Reify a, IConnection conn) => conn -> QueryBundle a -> IO (Exp a) runSQL c (Bundle queries) = do                              results <- mapM (runQuery c) queries                              let (queryMap, valueMap) = foldr buildRefMap ([],[]) results                              let ty = reify (undefined :: a)                              let results' = runReader (processResults 0 ty) (queryMap, valueMap)-                             return $ case lookup 1 results' of-                                         Just x -> x -                                         Nothing -> ListN [] ty+                             case ty of+                                 (ListT _) -> return $ fromMaybe (ListE []) (lookup 1 results')+                                 _         -> return $ fromJust (lookup 1 results')  -- | Type of the environment under which we reconstruct ordinary haskell data from the query result. -- The first component of the reader monad contains a mapping from (queryNumber, columnNumber) to @@ -141,49 +141,86 @@ findQuery :: (Int, Int) -> QueryR Int findQuery (q, c) = do                     env <- ask-                    return $ (\x -> case x of-                                  Just x' -> x'-                                  Nothing -> error $ show $ fst env) $ lookup (q, c + 1) $ fst env+                    return $ fromMaybe (error $ show $ fst env) $ lookup (q, c + 1) $ fst env  -- | Reconstruct the haskell value out of the result of query i with type ty.-processResults :: Int -> Type -> QueryR [(Int, Norm)]-processResults i ty@(ListT t1) = do+processResults :: Int -> Type a -> QueryR [(Int, Exp a)]+processResults i (ListT t1) = do                                 v <- getResults i                                 mapM (\(it, vals) -> do                                                         v1 <- processResults' i 0 vals t1-                                                        return (it, ListN v1 ty)) v+                                                        return (it, ListE v1)) v processResults i t = do                         v <- getResults i                         mapM (\(it, vals) -> do                                               v1 <- processResults' i 0 vals t                                               return (it, head v1)) v +nrColsInType :: Type a -> Int+nrColsInType UnitT = 1+nrColsInType BoolT = 1+nrColsInType CharT = 1+nrColsInType IntegerT = 1+nrColsInType DoubleT = 1+nrColsInType TextT = 1+nrColsInType (PairT t1 t2) = nrColsInType t1 + nrColsInType t2+nrColsInType (ListT _) = 1+nrColsInType (ArrowT _ _) = $impossible+ -- | Reconstruct the values for column c of query q out of the rawData vals with type t.-processResults' :: Int -> Int -> [[SqlValue]] -> Type -> QueryR [Norm]-processResults' _ _ vals UnitT = return $ map (\_ -> UnitN UnitT) vals-processResults' q c vals t@(TupleT t1 t2) = do+processResults' :: Int -> Int -> [[SqlValue]] -> Type a -> QueryR [Exp a]+processResults' _ _ vals UnitT = return $ map (\_ -> UnitE) vals+processResults' q c vals (PairT t1 t2) = do                                             v1s <- processResults' q c vals t1-                                            v2s <- processResults' q (c + 1) vals t2-                                            return $ [TupleN v1 v2 t | v1 <- v1s | v2 <- v2s]+                                            v2s <- processResults' q (c + nrColsInType t1) vals t2+                                            return (zipWith PairE v1s v2s) processResults' q c vals t@(ListT _) = do                                         nestQ <- findQuery (q, c)                                         list <- processResults nestQ t                                         i <- getColResPos q c-                                        let (maxV, vals') = foldr (\v (m,vs) -> let v' = (convert $ v !! i)::Int -                                                                                 in (m `max` v', v':vs))  (1,[]) vals+                                        let (maxV, vals') = foldr (\v (m,vs) -> let v' = sqlValueToInt (v !! i)+                                                                                in (m `max` v', v':vs))  (1,[]) vals                                         let maxI = if null list                                                     then 1-                                                    else fst $ L.maximumBy (\x y -> fst x `compare` fst y) list-                                        let lA = (A.accumArray ($impossible) Nothing (1,maxI `max` maxV) []) A.// map (\(x,y) -> (x, Just y)) list-                                        return $ map (\val -> case lA A.! val of-                                                                Just x -> x-                                                                Nothing -> ListN [] t) vals'-processResults' _ _ _ (ArrowT _ _) = $impossible -- The result cannot be a function+                                                    else fst $ L.maximumBy (compare `on` fst) list+                                        let lA = A.accumArray ($impossible) Nothing (1,maxI `max` maxV) [] A.// map (second Just) list+                                        return $ map (\val -> fromMaybe (ListE []) (lA A.! val)) vals'+processResults' _ _ _ (ArrowT _ _) = $impossible processResults' q c vals t = do                                     i <- getColResPos q c-                                    return $ map (\val -> convert $ (val !! i, t)) vals+                                    return $ map (\val -> convert (val !! i) t) vals +sqlValueToInt :: SqlValue -> Int+sqlValueToInt (SqlInteger i) = fromIntegral i+sqlValueToInt _ = $impossible +convert :: SqlValue -> Type a -> Exp a+convert SqlNull         UnitT    = UnitE+convert (SqlInteger i)  IntegerT = IntegerE i+convert (SqlInt32 i)    IntegerT = IntegerE $ fromIntegral i+convert (SqlInt64 i)    IntegerT = IntegerE $ fromIntegral i+convert (SqlWord32 i)   IntegerT = IntegerE $ fromIntegral i+convert (SqlWord64 i)   IntegerT = IntegerE $ fromIntegral i+convert (SqlDouble d)  DoubleT  = DoubleE d+convert (SqlRational d) DoubleT = DoubleE $ fromRational d+convert (SqlInteger d)  DoubleT = DoubleE $ fromIntegral d+convert (SqlInt32 d)    DoubleT = DoubleE $ fromIntegral d+convert (SqlInt64 d)    DoubleT = DoubleE $ fromIntegral d+convert (SqlWord32 d)   DoubleT = DoubleE $ fromIntegral d+convert (SqlWord64 d)   DoubleT = DoubleE $ fromIntegral d+convert (SqlBool b) BoolT       = BoolE b+convert (SqlInteger i) BoolT    = BoolE (i /= 0)+convert (SqlInt32 i)   BoolT    = BoolE (i /= 0)+convert (SqlInt64 i)   BoolT    = BoolE (i /= 0)+convert (SqlWord32 i)  BoolT    = BoolE (i /= 0)+convert (SqlWord64 i)  BoolT    = BoolE (i /= 0) +convert (SqlChar c) CharT       = CharE c+convert (SqlString (c:_)) CharT = CharE c+convert (SqlByteString c) CharT = CharE (head $ T.unpack $ T.decodeUtf8 c)+convert (SqlString t) TextT     = TextE (T.pack t) +convert (SqlByteString s) TextT = TextE (T.decodeUtf8 s)+convert sql                 _   = error $ "Unsupported SqlValue: "  ++ show sql+ -- | Partition by iter column -- The first argument is the position of the iter column. -- The second argument the raw data@@ -194,7 +231,7 @@                        in (i, v:vi) : partByIter n vr        where            getIter :: Int -> [SqlValue] -> Int-           getIter n' vals = ((fromSql (vals !! n'))::Int)+           getIter n' vals = fromSql (vals !! n') :: Int partByIter _ [] = []  @@ -224,11 +261,11 @@ -- | Transform algebraic plan scheme info into resultinfo schemeToResult :: SchemaInfo -> [(String, SqlColDesc)] -> ResultInfo schemeToResult (SchemaInfo itN cols) resDescr = let ordCols = sortBy (\(_, c1) (_, c2) -> compare c1 c2) cols-                                                    resColumns = flip zip [0..] $ map (\(c, _) -> takeWhile (\a -> a /= '_') c) resDescr+                                                    resColumns = flip zip [0..] $ map (\(c, _) -> takeWhile (/= '_') c) resDescr                                                     itC = fromJust $ lookup itN resColumns                                                  in ResultInfo itC $ map (\(n, _) -> (n, fromJust $ lookup n resColumns)) ordCols  -- |  buildRefMap :: (Int, ([(Int, [[SqlValue]])], ResultInfo, Maybe (Int, Int))) -> ([((Int, Int), Int)] ,[(Int, ([(Int, [[SqlValue]])], ResultInfo))]) -> ([((Int, Int), Int)] ,[(Int, ([(Int, [[SqlValue]])], ResultInfo))])-buildRefMap (q, (r, ri, (Just (t, c)))) (qm, rm) = (((t, c), q):qm, (q, (r, ri)):rm)+buildRefMap (q, (r, ri, Just (t, c))) (qm, rm) = (((t, c), q):qm, (q, (r, ri)):rm) buildRefMap (q, (r, ri, _)) (qm, rm) = (qm, (q, (r, ri)):rm)
src/Database/DSH/Compiler.hs view
@@ -3,13 +3,11 @@ -- FerryCore which is then translated into SQL (through a table algebra). The SQL -- code is executed on the database and then processed to form a Haskell value. -{-# LANGUAGE TemplateHaskell, MultiParamTypeClasses, ScopedTypeVariables #-}--module Database.DSH.Compiler (fromQ, debugPlan, debugCore, debugPlanOpt, debugSQL) where+module Database.DSH.Compiler (fromQ, debugPlan, debugCore, debugPlanOpt, debugSQL, debugCoreDot) where -import Database.DSH.Data as D-import Database.DSH.Impossible (impossible)-import Database.DSH.CSV (csvImport)+import Database.DSH.Internals as D+import Database.DSH.Impossible+import Database.DSH.CSV  import Database.DSH.Compile as C @@ -19,7 +17,6 @@ import qualified Data.Map as M import Data.Char import Database.HDBC-import Data.Convertible  import Control.Monad.State import Control.Applicative@@ -29,12 +26,10 @@ import Data.List (nub) import qualified Data.List as L -import Data.Generics (listify)- {- N monad, version of the state monad that can provide fresh variable names. -}-type N conn = StateT (conn, Int, M.Map String [(String, (FType -> Bool))]) IO+type N conn = StateT (conn, Int, M.Map String [(String,FType -> Bool)]) IO  -- | Provide a fresh identifier name during compilation freshVar :: N conn Int@@ -52,7 +47,7 @@ -- | Lookup information that describes a table. If the information is  -- not present in the state then the connection is used to retrieve the -- table information from the Database.-tableInfo :: IConnection conn => String -> N conn [(String, (FType -> Bool))]+tableInfo :: IConnection conn => String -> N conn [(String,FType -> Bool)] tableInfo t = do                (c, i, env) <- get                case M.lookup t env of@@ -64,7 +59,7 @@  -- | Turn a given integer into a variable beginning with prefix "__fv_"                     prefixVar :: Int -> String-prefixVar = ((++) "__fv_") . show+prefixVar = (++) "__fv_" . show       -- | Execute the transformation computation. During -- compilation table information can be retrieved from@@ -77,157 +72,167 @@  -- | Execute the query on the database fromQ :: (QA a, IConnection conn) => conn -> Q a -> IO a-fromQ c a = evaluate c a >>= (return . fromNorm)-+fromQ c (Q e) = fmap frExp (evaluate c e)  -- | Convert the query into unoptimised algebraic plan-debugPlan :: (QA a, IConnection conn) => conn -> Q a -> IO String+debugPlan :: (IConnection conn,Reify a) => conn -> Exp a -> IO String debugPlan = doCompile  -- | Convert the query into optimised algebraic plan-debugPlanOpt :: (QA a, IConnection conn) => conn -> Q a -> IO String+debugPlanOpt :: (IConnection conn,Reify a) => conn -> Exp a -> IO String debugPlanOpt q c = do                     p <- doCompile q c-                    (C.Algebra r) <- algToAlg ((C.Algebra p)::AlgebraXML a)+                    (C.Algebra r) <- algToAlg (C.Algebra p :: AlgebraXML a)                     return r -debugCore :: (QA a, IConnection conn) => conn -> Q a -> IO String-debugCore c (Q a) = do-                     core <- runN c $ transformE a-                     return $ show core+debugCore :: (IConnection conn,Reify a) => conn -> Exp a -> IO String+debugCore c a = do core <- runN c $ transformE a+                   return $ show core ++debugCoreDot :: (IConnection conn,Reify a) => conn -> Exp a -> IO String+debugCoreDot c a = do core <- runN c $ transformE a+                      return $ (\(Right d) -> d) $ dot core+ -- | Convert the query into SQL-debugSQL :: (QA a, IConnection conn) => conn -> Q a -> IO String-debugSQL q c = do-                p <- doCompile q c-                (C.SQL r) <- algToSQL ((C.Algebra p)::AlgebraXML a)-                return r+debugSQL :: (IConnection conn,Reify a) => conn -> Exp a -> IO String+debugSQL q c = do p <- doCompile q c+                  (C.SQL r) <- algToSQL (C.Algebra p :: AlgebraXML a)+                  return r  -- | evaluate compiles the given Q query into an executable plan, executes this and returns  -- the result as norm. For execution it uses the given connection. If the boolean flag is set -- to true it outputs the intermediate algebraic plan to disk.-evaluate :: forall a. forall conn. (QA a, IConnection conn)-         =>  conn-         -> Q a-         -> IO Norm-evaluate c q = do-                  algPlan' <- doCompile c q-                  let algPlan = ((C.Algebra algPlan') :: AlgebraXML a)+evaluate :: (Reify a, IConnection conn) => conn -> Exp a -> IO (Exp a)+evaluate c q = do algPlan' <- doCompile c q+                  let algPlan = C.Algebra algPlan' :: AlgebraXML a                   n <- executePlan c algPlan                   disconnect c                   return n  -- | Transform a query into an algebraic plan.                   -doCompile :: IConnection conn => conn -> Q a -> IO String-doCompile c (Q a) = do -                        core <- runN c $ transformE a-                        return $ typedCoreToAlgebra core+doCompile :: (IConnection conn, Reify a) => conn -> Exp a -> IO String+doCompile c a = do core <- runN c $ transformE a+                   return $ typedCoreToAlgebra core  -- | Transform the Query into a ferry core program.-transformE :: IConnection conn => Exp -> N conn CoreExpr-transformE (UnitE _) = return $ Constant ([] :=> int) $ CInt 1-transformE (BoolE b _) = return $ Constant ([] :=> bool) $ CBool b-transformE (CharE c _) = return $ Constant ([] :=> string) $ CString [c] -transformE (IntegerE i _) = return $ Constant ([] :=> int) $ CInt i-transformE (DoubleE d _) = return $ Constant ([] :=> float) $ CFloat d-transformE (TextE t _) = return $ Constant ([] :=> string) $ CString $ unpack t-transformE (TupleE e1 e2 ty) = do-                                        c1 <- transformE e1-                                        c2 <- transformE e2-                                        return $ Rec ([] :=> transformTy ty) [RecElem (typeOf c1) "1" c1, RecElem (typeOf c2) "2" c2] -transformE (ListE es ty) = let qt = ([] :=> transformTy ty) -                                  in foldr (\h t -> F.Cons qt h t) (Nil qt) <$> mapM transformE es-transformE (AppE1 f1 e1 ty) = do-                                      let tr = transformTy ty-                                      e1' <- transformArg e1-                                      let (_ :=> ta) = typeOf e1'-                                      return $ App ([] :=> tr) (transformF f1 (ta .-> tr)) e1'--- transformE ((AppE2 GroupWith fn e) ::: ty) = transformE $ ListE [e] ::: ty-transformE (AppE2 Span f e t@(TupleT t1 t2)) = transformE $ TupleE (AppE2 TakeWhile f e t1) (AppE2 DropWhile f e t2) t-transformE (AppE2 Break (LamE f _) e t@(TupleT t1 _)) = let notF = LamE (\x -> AppE1 Not (f x) BoolT) $ ArrowT t1 BoolT-                                                 in transformE $ AppE2 Span notF e t-transformE (AppE2 GroupWith gfn e ty@(ListT (ListT tel))) = do-                                                let tr = transformTy ty-                                                fn' <- transformArg gfn-                                                let (_ :=> tfn@(FFn _ rt)) = typeOf fn'-                                                let gtr = list $ rec [(RLabel "1", rt), (RLabel "2", transformTy $ ListT tel)]-                                                e' <- transformArg e-                                                let (_ :=> te) = typeOf e'-                                                fv <- transformArg (LamE id $ ArrowT tel tel)-                                                snd' <- transformArg (LamE (\x -> AppE1 Snd x $ ArrowT (TupleT (transformTy' rt) (ListT tel)) (ListT tel)) $ ArrowT (TupleT (transformTy' rt) (ListT tel)) (ListT tel))-                                                let (_ :=> sndTy) = typeOf snd'-                                                let (_ :=> tfv) = typeOf fv-                                                return $ App ([] :=> tr)-                                                            (App ([] :=> gtr .-> tr) (Var ([] :=> sndTy .-> gtr .-> tr) "map") snd') -                                                            (ParExpr ([] :=> gtr) $ App ([] :=> gtr)-                                                                (App ([] :=> te .-> gtr)-                                                                    (App ([] :=> tfn .-> te .-> gtr) (Var ([] :=> tfv .-> tfn .-> te .-> gtr) "groupWith") fv)-                                                                    fn'-                                                                )-                                                                e')-transformE (AppE2 D.Cons e1 e2 _) = do+transformE :: forall a conn. (IConnection conn, Reify a) => Exp a -> N conn CoreExpr+transformE (UnitE ) = return $ Constant ([] :=> int) $ CInt 1+transformE (BoolE b) = return $ Constant ([] :=> bool) $ CBool b+transformE (CharE c) = return $ Constant ([] :=> string) $ CString [c] +transformE (IntegerE i) = return $ Constant ([] :=> int) $ CInt i+transformE (DoubleE d) = return $ Constant ([] :=> float) $ CFloat d+transformE (TextE t) = return $ Constant ([] :=> string) $ CString $ unpack t+transformE (PairE e1 e2) = do let ty = reify (undefined :: a)+                              c1 <- transformE e1+                              c2 <- transformE e2+                              return $ Rec ([] :=> transformTy ty) [RecElem (typeOf c1) "1" c1, RecElem (typeOf c2) "2" c2] +transformE (ListE es) = let ty = reify (undefined :: a)+                            qt = ([] :=> transformTy ty) +                        in foldr (F.Cons qt) (Nil qt) <$> mapM transformE es+transformE (AppE GroupWith (PairE (gfn :: Exp (ta -> rt)) (e :: Exp el))) = do+  let ty = reify (undefined :: a)+  let tel = reify (undefined :: el)+  let tr = transformTy ty+  fn' <- transformLamArg gfn+  let (_ :=> tfn@(FFn _ rt)) = typeOf fn'+  let gtr = list $ rec [(RLabel "1", rt), (RLabel "2", transformTy $ ListT tel)]+  e' <- transformArg e+  let (_ :=> te) = typeOf e'+  fv <- transformLamArg (LamE id :: Exp (el -> el))+  snd' <- transformLamArg (LamE (\(x :: Exp (rt,[el])) -> AppE Snd x))+  let (_ :=> sndTy) = typeOf snd'+  let (_ :=> tfv) = typeOf fv+  return $ App ([] :=> tr)+              (App ([] :=> gtr .-> tr) (Var ([] :=> sndTy .-> gtr .-> tr) "map") snd') +              (ParExpr ([] :=> gtr) $ App ([] :=> gtr)+                  (App ([] :=> te .-> gtr)+                      (App ([] :=> tfn .-> te .-> gtr) (Var ([] :=> tfv .-> tfn .-> te .-> gtr) "groupWith") fv)+                      fn'+                  )+                  e')+transformE (AppE D.Cons (PairE e1 e2)) = do                                             e1' <- transformE e1                                             e2' <- transformE e2                                             let (_ :=> t) = typeOf e1'                                             return $ F.Cons ([] :=> list t) e1' e2'-transformE (AppE2 Append e1 e2 t) = transformE (AppE1 Concat (ListE [e1, e2] (ListT t)) t)-transformE (AppE2 Any f e _) = transformE $ AppE1 Or (AppE2 Map f e $ ListT BoolT) BoolT-transformE (AppE2 All f e _) = transformE $ AppE1 And (AppE2 Map f e $ ListT BoolT) BoolT-transformE (AppE2 Snoc e1 e2 t) = transformE (AppE2 Append e1 (ListE [e2] t) t)-transformE (AppE2 f2 e1 e2 ty) = do-                                        let tr = transformTy ty-                                        case elem f2 [Add, Sub, Mul, Div, Equ, Lt, Lte, Gte, Gt, Conj, Disj] of-                                            True  -> do-                                                      e1' <- transformE e1-                                                      e2' <- transformE e2-                                                      return $ BinOp ([] :=> tr) (transformOp f2) e1' e2'-                                            False -> do-                                                      e1' <- transformArg e1-                                                      e2' <- transformArg e2-                                                      let (_ :=> ta1) = typeOf e1'-                                                      let (_ :=> ta2) = typeOf e2'-                                                      return $ App ([] :=> tr) -                                                                (App ([] :=> ta2 .-> tr) (transformF f2 (ta1 .-> ta2 .-> tr)) e1')-                                                                e2'-transformE (AppE3 Cond e1 e2 e3 _) = do+transformE (AppE Cond (PairE e1 (PairE e2 e3))) = do                                              e1' <- transformE e1                                              e2' <- transformE e2                                              e3' <- transformE e3                                              let (_ :=> t) = typeOf e2'                                              return $ If ([] :=> t) e1' e2' e3'-transformE (AppE3 f3 e1 e2 e3 ty) = do-                                           let tr = transformTy ty-                                           e1' <- transformArg e1-                                           e2' <- transformArg e2-                                           e3' <- transformArg e3-                                           let (_ :=> ta1) = typeOf e1'-                                           let (_ :=> ta2) = typeOf e2'-                                           let (_ :=> ta3) = typeOf e3'-                                           return $ App ([] :=> tr)-                                                        (App ([] :=> ta3 .-> tr)-                                                             (App ([] :=> ta2 .-> ta3 .-> tr) (transformF f3 (ta1 .-> ta2 .-> ta3 .-> tr)) e1')-                                                             e2')-                                                        e3'-transformE (VarE i ty) = return $ Var ([] :=> transformTy ty) $ prefixVar i-transformE (TableE (TableCSV filepath) ty) = do-                                              norm1 <- lift (csvImport filepath ty)-                                              transformE (convert norm1)+transformE (AppE Fst (PairE e1 e2)) = do+  let ty = reify (undefined :: a)+  let tr = transformTy ty+  e1' <- transformArg (PairE e1 e2)+  let (_ :=> ta) = typeOf e1'+  return $ App ([] :=> tr) (transformF Fst (ta .-> tr)) e1'++transformE (AppE Snd (PairE e1 e2)) = do+  let ty = reify (undefined :: a)+  let tr = transformTy ty+  e1' <- transformArg (PairE e1 e2)+  let (_ :=> ta) = typeOf e1'+  return $ App ([] :=> tr) (transformF Snd (ta .-> tr)) e1'++transformE (AppE f2 (PairE (LamE f) e)) = do+  let ty = reify (undefined :: a)+  let tr = transformTy ty+  f' <- transformLamArg (LamE f)+  e' <- transformArg e+  let (_ :=> t1) = typeOf f'+  let (_ :=> t2) = typeOf e'+  return $ App ([] :=> tr)+              (App ([] :=> t2 .-> tr) (transformF f2 (t1 .-> t2 .-> tr)) f')+              e'++transformE (AppE f2 (PairE e1 e2)) = do+  let ty = reify (undefined :: a)+  let tr = transformTy ty+  if isOp f2+     then do e1' <- transformE e1+             e2' <- transformE e2+             return $ BinOp ([] :=> tr) (transformOp f2) e1' e2'+     else do e1' <- transformArg e1+             e2' <- transformArg e2+             let (_ :=> ta1) = typeOf e1'+             let (_ :=> ta2) = typeOf e2'+             return $ App ([] :=> tr) (App ([] :=> ta2 .-> tr) (transformF f2 (ta1 .-> ta2 .-> tr)) e1') e2'++transformE (AppE f1 e1) = do+  let ty = reify (undefined :: a)+  let tr = transformTy ty+  e1' <- transformArg e1+  let (_ :=> ta) = typeOf e1'+  return $ App ([] :=> tr) (transformF f1 (ta .-> tr)) e1'++transformE (VarE i) = do+  let ty = reify (undefined :: a)+  return $ Var ([] :=> transformTy ty) $ prefixVar $ fromIntegral i+  +transformE (TableE (TableCSV filepath)) = do+  let ty = reify (undefined :: a)+  e1 <- lift (csvImport filepath ty)+  transformE e1+ -- When a table node is encountered check that the given description -- matches the actual table information in the database.-transformE (TableE (TableDB n ks) ty) = do+transformE (TableE (TableDB n ks)) = do+                                    let ty = reify (undefined :: a)                                     fv <- freshVar                                     let tTy@(FList (FRec ts)) = flatFTy ty                                     let varB = Var ([] :=> FRec ts) $ prefixVar fv                                     tableDescr <- tableInfo n-                                    let tyDescr = case length tableDescr == length ts of-                                                    True -> zip tableDescr ts-                                                    False -> error $ "Inferred typed: " ++ show tTy ++ " \n doesn't match type of table: \"" -                                                                        ++ n ++ "\" in the database. The table has the shape: " ++ (show $ map fst tableDescr) ++ ". " ++ show ty +                                    let tyDescr = if length tableDescr == length ts+                                                    then zip tableDescr ts+                                                    else error $ "Inferred typed: " ++ show tTy ++ " \n doesn't match type of table: \"" +                                                                        ++ n ++ "\" in the database. The table has the shape: " ++ show (map fst tableDescr) ++ ". " ++ show ty                                      let cols = [Column cn t | ((cn, f), (RLabel i, t)) <- tyDescr, legalType n cn i t f]-                                    let keyCols = (nub $ concat ks) L.\\ (map fst tableDescr)-                                    let keys = if (keyCols == [])-                                                    then if (ks /= []) then map Key ks else [Key $ map (\(Column n' _) -> n') cols]-                                                    else error $ "The following columns were used as key but not a column of table " ++ n ++ " : " ++ show keyCols+                                    let keyCols = nub (concat ks) L.\\ map fst tableDescr+                                    let keys = if keyCols == []+                                                  then if ks /= [] then map Key ks else [Key $ map (\(Column n' _) -> n') cols]+                                                  else error $ "The following columns were used as key but not a column of table " ++ n ++ " : " ++ show keyCols                                     let table' = Table ([] :=> tTy) n cols keys                                     let pattern = [prefixVar fv]                                     let nameType = map (\(Column name t) -> (name, t)) cols @@ -245,81 +250,85 @@                                     return expr     where         legalType :: String -> String -> String -> FType -> (FType -> Bool) -> Bool-        legalType tn cn nr t f = case f t of-                                True -> True-                                False -> error $ "The type: " ++ show t ++ "\nis not compatible with the type of column nr: " ++ nr-                                                    ++ " namely: " ++ cn ++ "\n in table " ++ tn ++ "."-transformE (LamE _ _) = $impossible+        legalType tn cn nr t f = f t || error ( "The type: "+                                                ++ show t+                                                ++ "\nis not compatible with the type of column nr: " ++ nr+                                                ++ " namely: " ++ cn ++ "\n in table " ++ tn ++ ".")+transformE (LamE _) = $impossible --- | Transform a function argument-transformArg :: IConnection conn => Exp -> N conn Param                                 -transformArg (LamE f ty) = do-                                  n <- freshVar-                                  let (ArrowT t1 _) = ty-                                  let fty = transformTy ty-                                  let e1 = f $ VarE n t1-                                  case e1 of-                                    l@(LamE _ _) -> do-                                                     (ParAbstr _ vs e') <- transformArg l-                                                     return $ ParAbstr ([] :=> fty) ((prefixVar n):vs) e'-                                    _           -> ParAbstr ([] :=> fty) [prefixVar n] <$> transformE e1-transformArg e = (\e' -> ParExpr (typeOf e') e') <$> transformE e +transformLamArg :: forall a b conn. (IConnection conn) => Exp (a -> b) -> N conn Param+transformLamArg (LamE f) = do +  let ty = reify (undefined :: a -> b)+  n <- freshVar+  let fty = transformTy ty+  let e1 = f $ VarE $ fromIntegral n +  ParAbstr ([] :=> fty) [prefixVar n] <$> transformE e1+transformLamArg (AppE _ _) = $impossible+transformLamArg (VarE _)   = $impossible ++transformArg :: (IConnection conn,Reify a) => Exp a -> N conn Param+transformArg e = (\e' -> ParExpr (typeOf e') e') <$> transformE e+  -- | Construct a flat-FerryCore type out of a DSH type -- A flat type consists out of two tuples, a record is translated as: -- {r1 :: t1, r2 :: t2, r3 :: t3, r4 :: t4} (t1, (t2, (t3, t4)))-flatFTy :: Type -> FType+flatFTy :: Type a -> FType flatFTy (ListT t) = FList $ FRec $ flatFTy' 1 t  where-     flatFTy' :: Int -> Type -> [(RLabel, FType)]-     flatFTy' i (TupleT t1 t2) = (RLabel $ show i, transformTy t1) : (flatFTy' (i + 1) t2)-     flatFTy' i ty              = [(RLabel $ show i, transformTy ty)]+     flatFTy' :: Int -> Type a -> [(RLabel, FType)]+     flatFTy' i (PairT t1 t2) = (RLabel $ show i, transformTy t1) : flatFTy' (i + 1) t2+     flatFTy' i ty            = [(RLabel $ show i, transformTy ty)] flatFTy _         = $impossible  -- Determine the size of a flat type-sizeOfTy :: Type -> Int-sizeOfTy (TupleT _ t2) = 1 + sizeOfTy t2+sizeOfTy :: Type a -> Int+sizeOfTy (PairT _ t2) = 1 + sizeOfTy t2 sizeOfTy _              = 1   -- | Transform an arbitrary DSH-type into a ferry core type -transformTy :: Type -> FType+transformTy :: Type a -> FType transformTy UnitT = int transformTy BoolT = bool transformTy CharT = string transformTy TextT = string transformTy IntegerT = int transformTy DoubleT = float-transformTy (TupleT t1 t2) = FRec [(RLabel "1", transformTy t1), (RLabel "2", transformTy t2)]+transformTy (PairT t1 t2) = FRec [(RLabel "1", transformTy t1), (RLabel "2", transformTy t2)] transformTy (ListT t1) = FList $ transformTy t1-transformTy (ArrowT t1 t2) = (transformTy t1) .-> (transformTy t2)+transformTy (ArrowT t1 t2) = transformTy t1 .-> transformTy t2 --- | Transform a ferry-core type into a DSH-type-transformTy' :: FType -> Type-transformTy' FUnit = UnitT-transformTy' FInt  = IntegerT-transformTy' FFloat = DoubleT-transformTy' FString = TextT-transformTy' FBool = BoolT-transformTy' (FList t) = ListT $ transformTy' t-transformTy' (FRec [(RLabel "1", t1), (RLabel "2", t2)]) = TupleT (transformTy' t1) (transformTy' t2)-transformTy' (FFn t1 t2) = ArrowT (transformTy' t1) (transformTy' t2)-transformTy' _ = $impossible +isOp :: Fun a b -> Bool+isOp Add  = True+isOp Sub  = True+isOp Mul  = True+isOp Div  = True+isOp Equ  = True+isOp Lt   = True+isOp Lte  = True+isOp Gte  = True+isOp Gt   = True+isOp Conj = True+isOp Disj = True+isOp _    = False+ -- | Translate the DSH operator to Ferry Core operators-transformOp :: Fun2 -> Op-transformOp Add = Op "+"-transformOp Sub = Op "-"-transformOp Mul = Op "*"-transformOp Div = Op "/"-transformOp Equ = Op "=="-transformOp Lt = Op "<"-transformOp Lte = Op "<="-transformOp Gte = Op ">="-transformOp Gt = Op ">"+transformOp :: Fun a b -> Op+transformOp Add  = Op "+"+transformOp Sub  = Op "-"+transformOp Mul  = Op "*"+transformOp Div  = Op "/"+transformOp Equ  = Op "=="+transformOp Lt   = Op "<"+transformOp Lte  = Op "<="+transformOp Gte  = Op ">="+transformOp Gt   = Op ">" transformOp Conj = Op "&&" transformOp Disj = Op "||"-transformOp _ = $impossible+transformOp _    = $impossible + -- | Transform a DSH-primitive-function (f) with an instantiated typed into a FerryCore -- expression transformF :: (Show f) => f -> FType -> CoreExpr@@ -327,32 +336,21 @@                                             (x:xs) -> toLower x : xs                                             _      -> $impossible) $ show f --- | Retrieve all DB-table names from a DSH program-getTableNames :: Exp -> [String]-getTableNames e = let tables = map (\t -> case t of-                                        (TableE (TableDB n _) _) -> n-                                        _                        -> $impossible) $ listify isTable e-                   in nub tables-    where -        isTable :: Exp -> Bool-        isTable (TableE (TableDB _ _) _) = True-        isTable _                        = False- -- | Retrieve through the given database connection information on the table (columns with their types) -- which name is given as the second argument.        -getTableInfo :: IConnection conn => conn -> String -> IO [(String, (FType -> Bool))]+getTableInfo :: IConnection conn => conn -> String -> IO [(String,FType -> Bool)] getTableInfo c n = do                     info <- describeTable c n                     return $ toTableDescr info                              where-          toTableDescr :: [(String, SqlColDesc)] -> [(String, (FType -> Bool))]+          toTableDescr :: [(String, SqlColDesc)] -> [(String,FType -> Bool)]           toTableDescr = L.sortBy (\(n1, _) (n2, _) -> compare n1 n2) . map (\(name, props) -> (name, compatibleType (colType props)))           compatibleType :: SqlTypeId -> FType -> Bool           compatibleType dbT hsT = case hsT of-                                        FUnit -> True-                                        FBool -> L.elem dbT [SqlSmallIntT, SqlIntegerT, SqlBitT]-                                        FString -> L.elem dbT [SqlCharT, SqlWCharT, SqlVarCharT]-                                        FInt -> L.elem dbT [SqlSmallIntT, SqlIntegerT, SqlTinyIntT, SqlBigIntT, SqlNumericT]-                                        FFloat -> L.elem dbT [SqlDecimalT, SqlRealT, SqlFloatT, SqlDoubleT]+                                        FUnit   -> True+                                        FBool   -> dbT `L.elem` [SqlSmallIntT, SqlIntegerT, SqlBitT]+                                        FString -> dbT `L.elem` [SqlCharT, SqlWCharT, SqlVarCharT]+                                        FInt    -> dbT `L.elem` [SqlSmallIntT, SqlIntegerT, SqlTinyIntT, SqlBigIntT, SqlNumericT]+                                        FFloat  -> dbT `L.elem` [SqlDecimalT, SqlRealT, SqlFloatT, SqlDoubleT]                                         t       -> error $ "You can't store this kind of data in a table... " ++ show t ++ " " ++ show n
− src/Database/DSH/Data.hs
@@ -1,463 +0,0 @@-{-# LANGUAGE TemplateHaskell, ViewPatterns, ScopedTypeVariables, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, DeriveDataTypeable #-}--module Database.DSH.Data where--import Database.DSH.Impossible--import Data.Convertible-import Data.Typeable-import Database.HDBC-import Data.Generics-import Data.Text(Text)-import qualified Data.Text as T-import qualified Data.Text.Encoding as T--import GHC.Exts--data Exp =-    UnitE Type-  | BoolE Bool Type-  | CharE Char Type-  | IntegerE Integer Type-  | DoubleE Double Type-  | TextE Text Type-  | TupleE Exp Exp Type-  | ListE [Exp] Type-  | LamE (Exp -> Exp) Type-  | AppE1 Fun1 Exp Type-  | AppE2 Fun2 Exp Exp Type-  | AppE3 Fun3 Exp Exp Exp Type-  | TableE Table Type-  | VarE Int Type-   deriving (Show, Data, Typeable)--instance Show (Exp -> Exp) where-  show _ = "(f :: Exp -> Exp)"--data Fun1 =-    Fst | Snd | Not | IntegerToDouble-  | Head | Tail | Unzip | Minimum-  | Maximum | Concat | Sum | And-  | Or | Reverse | Length | Null | Init-  | Last | The | Nub-  deriving (Eq, Ord, Show, Data, Typeable)---data Fun2 =-    Add | Mul | Sub | Div | All | Any | Index-  | SortWith | Cons | Snoc | Take | Drop-  | Map | Append | Filter | GroupWith | Zip-  | Break | Span | DropWhile | TakeWhile-  | SplitAt | Equ | Conj | Disj-  | Lt | Lte | Gte | Gt | Max | Min-  deriving (Eq, Ord, Show, Data, Typeable)--data Fun3 = Cond | ZipWith-  deriving (Eq, Ord, Show, Data, Typeable)---data Norm =-    UnitN Type-  | BoolN Bool Type-  | CharN Char Type-  | IntegerN Integer Type-  | DoubleN Double Type-  | TextN Text Type-  | TupleN Norm Norm Type-  | ListN [Norm] Type-  deriving (Eq, Ord, Show, Data, Typeable)--data Type =-    UnitT-  | BoolT-  | CharT-  | IntegerT-  | DoubleT-  | TextT-  | TupleT Type Type-  | ListT Type-  | ArrowT Type Type-  deriving (Eq, Ord, Show, Data, Typeable)---data Table =-    TableDB   String [[String]]-  | TableCSV  String-  deriving (Eq, Ord, Show, Data, Typeable)---typeExp :: Exp -> Type-typeExp e = case e of-  UnitE t -> t-  BoolE _ t -> t-  CharE _ t -> t-  IntegerE _ t -> t-  DoubleE _ t -> t-  TextE _ t -> t-  TupleE _ _ t -> t-  ListE _ t -> t-  LamE _ t -> t-  AppE1 _ _ t -> t-  AppE2 _ _ _ t -> t-  AppE3 _ _ _ _ t -> t-  TableE _ t -> t-  VarE _ t -> t--typeArrowResult :: Type -> Type-typeArrowResult (ArrowT _ t) = t-typeArrowResult _ = $impossible--typeTupleFst :: Type -> Type-typeTupleFst (TupleT a _) = a-typeTupleFst _ = $impossible--typeTupleSnd :: Type -> Type-typeTupleSnd (TupleT _ b) = b-typeTupleSnd _ = $impossible--typeNorm :: Norm -> Type-typeNorm = typeExp . convert--data Q a = Q Exp deriving (Show, Data, Typeable)--class QA a where-  reify :: a -> Type-  toNorm :: a -> Norm-  fromNorm :: Norm -> a--instance QA () where-  reify _ = UnitT-  toNorm _ = UnitN UnitT-  fromNorm (UnitN UnitT) = ()-  fromNorm _ = $impossible--instance QA Bool where-  reify _ = BoolT-  toNorm b = BoolN b BoolT-  fromNorm (BoolN b BoolT) = b-  fromNorm v = $impossible--instance QA Char where-  reify _ = CharT-  toNorm c = CharN c CharT-  fromNorm (CharN c CharT) = c-  fromNorm _ = $impossible--instance QA Integer where-  reify _ = IntegerT-  toNorm i = IntegerN i IntegerT-  fromNorm (IntegerN i IntegerT) = i-  fromNorm _ = $impossible--instance QA Double where-  reify _ = DoubleT-  toNorm d = DoubleN d DoubleT-  fromNorm (DoubleN i DoubleT) = i-  fromNorm _ = $impossible--instance QA Text where-    reify _ = TextT-    toNorm t = TextN t TextT-    fromNorm (TextN t TextT) = t-    fromNorm _ = $impossible--instance (QA a,QA b) => QA (a,b) where-  reify _ = TupleT (reify (undefined :: a)) (reify (undefined :: b))-  toNorm (a,b) = TupleN (toNorm a) (toNorm b) (reify (a,b))-  fromNorm (TupleN a b (TupleT _ _)) = (fromNorm a,fromNorm b)-  fromNorm _ = $impossible--instance (QA a) => QA [a] where-  reify _ = ListT (reify (undefined :: a))-  toNorm as = ListN (map toNorm as) (reify as)-  fromNorm (ListN as (ListT _)) = map fromNorm as-  fromNorm _ = $impossible--instance (QA a) => QA (Maybe a) where-  reify _ = reify ([] :: [a])--  toNorm Nothing  = toNorm ([] :: [a])-  toNorm (Just x) = toNorm [x]--  fromNorm ma = case (fromNorm ma) :: [a] of-                  []      -> Nothing-                  (x : _) -> Just x--instance (QA a,QA b) => QA (Either a b) where-  reify _ = reify (([],[]) :: ([a],[b]))--  toNorm (Left  x) = toNorm ([x],[] :: [b])-  toNorm (Right x) = toNorm ([] :: [a],[x])--  fromNorm e =  case (fromNorm e) :: ([a],[b]) of-                  ([],x : _) -> Right x-                  (x : _,[]) -> Left  x-                  _          -> $impossible---tupleToEither :: (QA a,QA b) => Q ([a],[b]) -> Q (Either a b)-tupleToEither (Q x) = (Q x)--eitherToTuple :: (QA a,QA b) => Q (Either a b) -> Q ([a],[b])-eitherToTuple (Q x) = (Q x)--class BasicType a where--instance BasicType () where-instance BasicType Bool where-instance BasicType Char where-instance BasicType Integer where-instance BasicType Double where-instance BasicType Text where---- * Refering to Real Database Tables--class (QA a) => TA a where-  tablePersistence :: Table -> Q [a]-  tablePersistence t = Q (TableE t (reify (undefined :: [a])))---table :: (TA a) => String -> Q [a]-table = tableDB--tableDB :: (TA a) => String -> Q [a]-tableDB name = tablePersistence (TableDB name [])--tableWithKeys :: (TA a) => String -> [[String]] -> Q [a]-tableWithKeys name keys = tablePersistence (TableDB name keys)--tableCSV :: (TA a) => String -> Q [a]-tableCSV filename = tablePersistence (TableCSV filename)---instance TA () where-instance TA Bool where-instance TA Char where-instance TA Integer where-instance TA Double where-instance TA Text where-instance (BasicType a, BasicType b, QA a, QA b) => TA (a,b) where---- * Eq, Ord and Num Instances for Databse Queries--instance Eq (Q Integer) where-  (==) _ _ = error "Eq instance for (Q Integer) must not be used."--instance Eq (Q Double) where-  (==) _ _ = error "Eq instance for (Q Double) must not be used."--instance Num (Q Integer) where-  (+) (Q e1) (Q e2) = Q (AppE2 Add e1 e2 IntegerT)-  (*) (Q e1) (Q e2) = Q (AppE2 Mul e1 e2 IntegerT)-  (-) (Q e1) (Q e2) = Q (AppE2 Sub e1 e2 IntegerT)--  fromInteger i = Q (IntegerE i      IntegerT)--  abs (Q e1) =-    let zero      = IntegerE 0 IntegerT-        e1Negated = AppE2 Sub zero e1 IntegerT-    in Q (AppE3 Cond (AppE2 Lt e1 zero BoolT) e1Negated e1 IntegerT)--  signum (Q e1) =-    let zero     = IntegerE 0 IntegerT-        one      = IntegerE 1 IntegerT-        minusOne = IntegerE (negate 1) IntegerT-    in Q (AppE3 Cond (AppE2 Lt e1 zero BoolT)-                     (minusOne)-                     (AppE3 Cond (AppE2 Equ e1 zero BoolT) zero one IntegerT)-                     IntegerT)--instance Num (Q Double) where-  (+) (Q e1) (Q e2) = Q (AppE2 Add e1 e2 DoubleT)-  (*) (Q e1) (Q e2) = Q (AppE2 Mul e1 e2 DoubleT)-  (-) (Q e1) (Q e2) = Q (AppE2 Sub e1 e2 DoubleT)--  fromInteger d     = Q (DoubleE (fromIntegral d) DoubleT)--  abs (Q e1) =-    let zero      = DoubleE 0.0 DoubleT-        e1Negated = AppE2 Sub zero e1 DoubleT-    in Q (AppE3 Cond (AppE2 Lt e1 zero BoolT) e1Negated e1 DoubleT)--  signum (Q e1) =-    let zero     = DoubleE 0.0 DoubleT-        one      = DoubleE 1.0 DoubleT-        minusOne = DoubleE (negate 1.0) DoubleT-    in Q (AppE3 Cond (AppE2 Lt e1 zero BoolT)-                     (minusOne)-                     (AppE3 Cond (AppE2 Equ e1 zero BoolT) zero one DoubleT)-                     DoubleT)---instance Fractional (Q Double) where-  (/) (Q e1) (Q e2) = Q (AppE2 Div e1 e2          DoubleT)-  fromRational r    = Q (DoubleE (fromRational r) DoubleT)---- * Support for View Patterns--class View a b | a -> b, b -> a where-  view :: a -> b-  fromView :: b -> a--tuple :: (View a b) => b -> a-tuple = fromView--record :: (View a b) => b -> a-record = fromView--instance View (Q ()) (Q ()) where-  view = id-  fromView = id--instance View (Q Bool) (Q Bool) where-  view = id-  fromView = id--instance View (Q Char) (Q Char) where-  view = id-  fromView = id--instance View (Q Integer) (Q Integer) where-  view = id-  fromView = id--instance View (Q Double) (Q Double) where-  view = id-  fromView = id--instance View (Q Text) (Q Text) where-  view = id-  fromView = id--instance (QA a,QA b) => View (Q (a,b)) (Q a, Q b) where-  view (Q a) = (Q (AppE1 Fst a (reify (undefined :: a))), Q (AppE1 Snd a (reify (undefined :: b))))-  fromView ((Q e1),(Q e2)) = Q (TupleE e1 e2 (reify (undefined :: (a, b))))--instance Convertible Norm Exp where-    safeConvert n = Right $-        case n of-             UnitN t        -> UnitE t-             BoolN b t      -> BoolE b t-             CharN c t      -> CharE c t-             TextN s t      -> TextE s t-             IntegerN i t   -> IntegerE i t-             DoubleN d t    -> DoubleE d t-             TupleN n1 n2 t -> TupleE (convert n1) (convert n2) t-             ListN ns t     -> ListE (map convert ns) t--forget :: (QA a) => Q a -> Exp-forget (Q a) = a--toLam1 :: forall a b. (QA a,QA b) => (Q a -> Q b) -> Exp-toLam1 f = LamE (forget . f . Q) (ArrowT (reify (undefined :: a)) (reify (undefined :: b)))--toLam2 :: forall a b c. (QA a,QA b,QA c) => (Q a -> Q b -> Q c) -> Exp-toLam2 f =-  let f1 = \a b -> forget (f (Q a) (Q b))-      t1 = ArrowT (reify (undefined :: b)) (reify (undefined :: c))-      f2 = \a -> LamE (\b -> f1 a b) t1-      t2 = ArrowT (reify (undefined :: a)) t1-  in  LamE f2 t2--unfoldType :: Type -> [Type]-unfoldType (TupleT t1 t2) = t1 : unfoldType t2-unfoldType t = [t]--instance Convertible Type SqlTypeId where-    safeConvert n =-        case n of-             IntegerT       -> Right SqlBigIntT-             DoubleT        -> Right SqlDoubleT-             BoolT          -> Right SqlBitT-             CharT          -> Right SqlCharT-             TextT          -> Right SqlVarCharT-             UnitT          -> convError "No `UnitT' representation" n-             TupleT {}      -> convError "No `TupleT' representation" n-             ListT {}       -> convError "No `ListT' representation" n-             ArrowT {}      -> convError "No `ArrowT' representation" n--instance Convertible SqlTypeId Type where-    safeConvert n =-        case n of-          SqlCharT           -> Right TextT-          SqlVarCharT        -> Right TextT-          SqlLongVarCharT    -> Right TextT-          SqlWCharT          -> Right TextT-          SqlWVarCharT       -> Right TextT-          SqlWLongVarCharT   -> Right TextT-          SqlDecimalT        -> Right DoubleT-          SqlNumericT        -> Right DoubleT-          SqlSmallIntT       -> Right IntegerT-          SqlIntegerT        -> Right IntegerT-          SqlRealT           -> Right DoubleT-          SqlFloatT          -> Right DoubleT-          SqlDoubleT         -> Right DoubleT-          SqlBitT            -> Right BoolT-          SqlBigIntT         -> Right IntegerT-          SqlTinyIntT        -> Right IntegerT-          _                  -> convError "Unsupported `SqlTypeId'" n---instance Convertible SqlValue Norm where-    safeConvert sql =-        case sql of-             SqlNull            -> Right $ UnitN UnitT-             SqlInteger i       -> Right $ IntegerN i IntegerT-             SqlDouble d        -> Right $ DoubleN d DoubleT-             SqlBool b          -> Right $ BoolN b BoolT-             SqlChar c          -> Right $ CharN c CharT-             SqlString t        -> Right $ TextN (T.pack t) TextT-             SqlByteString s    -> Right $ TextN (T.decodeUtf8 s) TextT-             _                  -> convError "Unsupported `SqlValue'" sql--instance Convertible (SqlValue, Type) Norm where-    safeConvert sql =-        case sql of-          (SqlNull, UnitT)         -> Right $ UnitN UnitT--          (SqlInteger i, IntegerT) -> Right $ IntegerN i IntegerT-          (SqlInt32 i, IntegerT)   -> Right $ flip IntegerN IntegerT $ convert i-          (SqlInt64 i, IntegerT)   -> Right $ flip IntegerN IntegerT $ convert i-          (SqlWord32 i, IntegerT)  -> Right $ flip IntegerN IntegerT $ convert i-          (SqlWord64 i, IntegerT)  -> Right $ flip IntegerN IntegerT $ convert i-          (SqlRational r, IntegerT) -> Right $ flip IntegerN IntegerT $ convert r--          (SqlDouble d, DoubleT)   -> Right $ DoubleN d DoubleT-          (SqlRational r, DoubleT) -> Right $ flip DoubleN DoubleT $ convert r-          (SqlInteger i, DoubleT)  -> Right $ flip DoubleN DoubleT $ convert i-          (SqlInt32 i, DoubleT)    -> Right $ flip DoubleN DoubleT $ convert i-          (SqlInt64 i, DoubleT)    -> Right $ flip DoubleN DoubleT $ convert i-          (SqlWord32 i, DoubleT)   -> Right $ flip DoubleN DoubleT $ convert i-          (SqlWord64 i, DoubleT)   -> Right $ flip DoubleN DoubleT $ convert i--          (SqlBool b, BoolT)       -> Right $ BoolN b BoolT-          (SqlInteger i, BoolT)    -> Right $ BoolN (i == 1) BoolT-          (SqlInt32 i, BoolT)      -> Right $ BoolN (i == 1) BoolT-          (SqlInt64 i, BoolT)      -> Right $ BoolN (i == 1) BoolT-          (SqlWord32 i, BoolT)     -> Right $ BoolN (i == 1) BoolT-          (SqlWord64 i, BoolT)     -> Right $ BoolN (i == 1) BoolT--          (SqlString s, TextT)     -> Right $ TextN (T.pack s) TextT-          (SqlByteString s, TextT) -> Right $ TextN (T.decodeUtf8 s) TextT--          (SqlChar c, CharT) -> Right $ CharN c CharT-          (SqlString (c : _), CharT) -> Right $ CharN c CharT-          (SqlByteString ((T.unpack . T.decodeUtf8) -> (c : _)), CharT)  -> Right $ CharN c CharT--          _                        -> $impossible--instance Convertible Norm SqlValue where-    safeConvert n =-        case n of-             UnitN _             -> Right $ SqlNull-             IntegerN i _        -> Right $ SqlInteger i-             DoubleN d _         -> Right $ SqlDouble d-             BoolN b _           -> Right $ SqlBool b-             CharN c _           -> Right $ SqlChar c-             TextN t _           -> Right $ SqlString $ T.unpack t-             ListN _ _           -> convError "Cannot convert `Norm' to `SqlValue'" n-             TupleN _ _ _        -> convError "Cannot convert `Norm' to `SqlValue'" n---instance IsString (Q Text) where-  fromString s = Q (TextE (T.pack s) TextT)
+ src/Database/DSH/Externals.hs view
@@ -0,0 +1,647 @@+module Database.DSH.Externals where++import Database.DSH.Internals+import Database.DSH.Impossible+import Database.DSH.TH++import Prelude ( Eq, Ord, Num(..), Fractional(..), Show(..)+               , Bool(..), Char, Integer, Double, String, Maybe(..), Either(..)+               , id, undefined, ($), (.))+import qualified Prelude as P++import Data.String+import Data.Text (Text)+import qualified Data.Text as T++-- QA Instances++instance QA () where+  type Rep () = ()+  toExp () = UnitE+  frExp UnitE = ()+  frExp _ = $impossible++instance QA Bool where+  type Rep Bool = Bool+  toExp = BoolE+  frExp (BoolE b) = b+  frExp _ = $impossible++instance QA Char where+  type Rep Char = Char+  toExp = CharE+  frExp (CharE c) = c+  frExp _ = $impossible++instance QA Integer where+  type Rep Integer = Integer+  toExp = IntegerE+  frExp (IntegerE i) = i+  frExp _ = $impossible++instance QA Double where+  type Rep Double = Double+  toExp = DoubleE+  frExp (DoubleE d) = d+  frExp _ = $impossible++instance QA Text where+  type Rep Text = Text+  toExp = TextE+  frExp (TextE t) = t+  frExp _ = $impossible++instance (QA a, QA b) => QA (a,b) where+  type Rep (a,b) = (Rep a,Rep b)+  toExp (a,b) = PairE (toExp a) (toExp b)+  frExp (PairE a b) = (frExp a,frExp b)+  frExp _ = $impossible++instance (QA a) => QA [a] where+  type Rep [a] = [Rep a]+  toExp as = ListE (P.map toExp as)+  frExp (ListE as) = P.map frExp as+  frExp _ = $impossible++instance (QA a) => QA (Maybe a) where+  type Rep (Maybe a) = [Rep a]+  toExp Nothing = ListE []+  toExp (Just a) = ListE [toExp a]+  frExp (ListE []) = Nothing+  frExp (ListE (a : _)) = Just (frExp a)+  frExp _ = $impossible++instance (QA a,QA b) => QA (Either a b) where+  type Rep (Either a b) = ([Rep a],[Rep b])+  toExp (Left a) = PairE (ListE [toExp a]) (ListE [])+  toExp (Right b) = PairE (ListE []) (ListE [toExp b])+  frExp (PairE (ListE (a : _)) _) = Left (frExp a)+  frExp (PairE _ (ListE (a : _))) = Right (frExp a)+  frExp _ = $impossible++-- Elim instances++instance (QA r) => Elim () r where+  type Eliminator () r = Q r -> Q r+  elim _ r = r++instance (QA r) => Elim Bool r where+  type Eliminator Bool r = Q r -> Q r -> Q r+  elim (Q e) (Q e1) (Q e2) = Q (AppE Cond (PairE e (PairE e1 e2)))++instance (QA r) => Elim Char r where+  type Eliminator Char r = (Q Char -> Q r) -> Q r+  elim q f = f q++instance (QA r) => Elim Integer r where+  type Eliminator Integer r = (Q Integer -> Q r) -> Q r+  elim q f = f q++instance (QA r) => Elim Double r where+  type Eliminator Double r = (Q Double -> Q r) -> Q r+  elim q f = f q++instance (QA r) => Elim Text r where+  type Eliminator Text r = (Q Text -> Q r) -> Q r+  elim q f = f q++instance (QA a,QA b,QA r) => Elim (a,b) r where+  type Eliminator (a,b) r = (Q a -> Q b -> Q r) -> Q r+  elim q f = f (fst q) (snd q)++instance (QA a,QA r) => Elim (Maybe a) r where+  type Eliminator (Maybe a) r = Q r -> (Q a -> Q r) -> Q r+  elim q r f = maybe r f q++instance (QA a,QA b,QA r) => Elim (Either a b) r where+  type Eliminator (Either a b) r = (Q a -> Q r) -> (Q b -> Q r) -> Q r+  elim q f g = either f g q++-- BasicType instances++instance BasicType () where+instance BasicType Bool where+instance BasicType Char where+instance BasicType Integer where+instance BasicType Double where+instance BasicType Text where++-- TA instances++instance TA () where+instance TA Bool where+instance TA Char where+instance TA Integer where+instance TA Double where+instance TA Text where+instance (BasicType a, BasicType b) => TA (a,b) where++-- Num and Fractional instances++instance Num (Exp Integer) where+  (+) e1 e2 = AppE Add (PairE e1 e2)+  (*) e1 e2 = AppE Mul (PairE e1 e2)+  (-) e1 e2 = AppE Sub (PairE e1 e2)++  fromInteger = IntegerE++  abs e = let c = AppE Lt (PairE e 0)+          in  AppE Cond (PairE c (PairE (negate e) e))++  signum e = let c1 = AppE Lt  (PairE e 0)+                 c2 = AppE Equ (PairE e 0)+                 e' = AppE Cond (PairE c2 (PairE 0 1))+             in  AppE Cond (PairE c1 (PairE (-1) e'))++instance Num (Exp Double) where+  (+) e1 e2 = AppE Add (PairE e1 e2)+  (*) e1 e2 = AppE Mul (PairE e1 e2)+  (-) e1 e2 = AppE Sub (PairE e1 e2)++  fromInteger = DoubleE . fromInteger++  abs e = let c = AppE Lt (PairE e 0)+          in  AppE Cond (PairE c (PairE (negate e) e))++  signum e = let c1 = AppE Lt  (PairE e 0.0)+                 c2 = AppE Equ (PairE e 0.0)+                 e' = AppE Cond (PairE c2 (PairE 0 1))+             in  AppE Cond (PairE c1 (PairE (-1) e'))++instance Fractional (Exp Double) where+  (/) e1 e2    = AppE Div (PairE e1 e2)+  fromRational = DoubleE . fromRational++instance Num (Q Integer) where+  (+) (Q e1) (Q e2) = Q (e1 + e2)+  (*) (Q e1) (Q e2) = Q (e1 * e2)+  (-) (Q e1) (Q e2) = Q (e1 - e2)+  fromInteger       = Q . IntegerE+  abs (Q e)         = Q (abs e)+  signum (Q e)      = Q (signum e)++instance Num (Q Double) where+  (+) (Q e1) (Q e2) = Q (e1 + e2)+  (*) (Q e1) (Q e2) = Q (e1 * e2)+  (-) (Q e1) (Q e2) = Q (e1 - e2)+  fromInteger       = Q . DoubleE . fromInteger+  abs (Q e)         = Q (abs e)+  signum (Q e)      = Q (signum e)++instance Fractional (Q Double) where+  (/) (Q e1) (Q e2) = Q (e1 / e2)+  fromRational = Q . DoubleE . fromRational++-- View instances++instance View (Q ()) (Q ()) where+  type ToView (Q ()) = Q ()+  type FromView (Q ()) = Q ()+  view = id+  fromView = id++instance View (Q Bool) (Q Bool) where+  type ToView (Q Bool) = Q Bool+  type FromView (Q Bool) = Q Bool+  view = id+  fromView = id++instance View (Q Char) (Q Char) where+  type ToView (Q Char) = Q Char+  type FromView (Q Char) = Q Char+  view = id+  fromView = id++instance View (Q Integer) (Q Integer) where+  type ToView (Q Integer) = Q Integer+  type FromView (Q Integer) = Q Integer+  view = id+  fromView = id++instance View (Q Double) (Q Double) where+  type ToView (Q Double) = Q Double+  type FromView (Q Double) = Q Double+  view = id+  fromView = id++instance View (Q Text) (Q Text) where+  type ToView (Q Text) = Q Text+  type FromView (Q Text) = Q Text+  view = id+  fromView = id++instance (QA a, QA b) => View (Q (a,b)) (Q a,Q b) where+  type ToView (Q (a,b)) = (Q a,Q b)+  type FromView (Q a,Q b) = (Q (a,b))+  view (Q e) = (Q (AppE Fst e),Q (AppE Snd e))+  fromView (Q a,Q b) = Q (PairE a b)++-- IsString instances++instance IsString (Q Text) where+  fromString = Q . TextE . T.pack++-- * Referring to persistent tables++table :: (QA a, TA a) => String -> Q [a]+table name = Q (TableE (TableDB name []))++tableDB :: (QA a, TA a) => String -> Q [a]+tableDB name = Q (TableE (TableDB name []))++tableWithKeys :: (QA a, TA a) => String -> [[String]] -> Q [a]+tableWithKeys name keys = Q (TableE (TableDB name keys))++tableCSV :: (QA a, TA a) => String -> Q [a]+tableCSV filename = Q (TableE (TableCSV filename))++-- * toQ++toQ :: (QA a) => a -> Q a+toQ = Q . toExp++-- * Unit++unit :: Q ()+unit = Q UnitE++-- * Boolean logic++false :: Q Bool+false = Q (BoolE False)++true :: Q Bool+true = Q (BoolE True)++not :: Q Bool -> Q Bool+not (Q e) = Q (AppE Not e)++(&&) :: Q Bool -> Q Bool -> Q Bool+(&&) (Q a) (Q b) = Q (AppE Conj (PairE a b))++(||) :: Q Bool -> Q Bool -> Q Bool+(||) (Q a) (Q b) = Q (AppE Disj (PairE a b))++-- * Equality and Ordering++eq :: (QA a,Eq a) => Q a -> Q a -> Q Bool+eq (Q a) (Q b) = Q (AppE Equ (PairE a b))++(==) :: (QA a,Eq a) => Q a -> Q a -> Q Bool+(==) = eq++neq :: (QA a,Eq a) => Q a -> Q a -> Q Bool+neq a b = not (eq a b)++(/=) :: (QA a,Eq a) => Q a -> Q a -> Q Bool+(/=) = neq++lt :: (QA a,Ord a) => Q a -> Q a -> Q Bool+lt (Q a) (Q b) = Q (AppE Lt (PairE a b))++(<) :: (QA a,Ord a) => Q a -> Q a -> Q Bool+(<) = lt++lte :: (QA a,Ord a) => Q a -> Q a -> Q Bool+lte (Q a) (Q b) = Q (AppE Lte (PairE a b))++(<=) :: (QA a,Ord a) => Q a -> Q a -> Q Bool+(<=) = lte++gte :: (QA a,Ord a) => Q a -> Q a -> Q Bool+gte (Q a) (Q b) = Q (AppE Gte (PairE a b))++(>=) :: (QA a,Ord a) => Q a -> Q a -> Q Bool+(>=) = gte++gt :: (QA a,Ord a) => Q a -> Q a -> Q Bool+gt (Q a) (Q b) = Q (AppE Gt (PairE a b))++(>) :: (QA a,Ord a) => Q a -> Q a -> Q Bool+(>) = gt++min :: (QA a,Ord a) => Q a -> Q a -> Q a+min (Q a) (Q b) = Q (AppE Min (PairE a b))++max :: (QA a,Ord a) => Q a -> Q a -> Q a+max (Q a) (Q b) = Q (AppE Max (PairE a b))++-- * Conditionals++bool :: (QA a) => Q a -> Q a -> Q Bool -> Q a+bool f t b = cond b t f++cond :: (QA a) => Q Bool -> Q a -> Q a -> Q a+cond (Q c) (Q a) (Q b) = Q (AppE Cond (PairE c (PairE a b)))++(?) :: (QA a) => Q Bool -> (Q a,Q a) -> Q a+(?) c (a,b) = cond c a b++-- * Maybe++listToMaybe :: (QA a) => Q [a] -> Q (Maybe a)+listToMaybe (Q as) = Q as++maybeToList :: (QA a) => Q (Maybe a) -> Q [a]+maybeToList (Q ma) = Q ma++nothing :: (QA a) => Q (Maybe a)+nothing = listToMaybe nil++just :: (QA a) => Q a -> Q (Maybe a)+just a = listToMaybe (singleton a)++isNothing :: (QA a) => Q (Maybe a) -> Q Bool+isNothing ma = null (maybeToList ma)++isJust :: (QA a) => Q (Maybe a) -> Q Bool+isJust ma = not (isNothing ma)++fromJust :: (QA a) => Q (Maybe a) -> Q a+fromJust ma = head (maybeToList ma)++maybe :: (QA a,QA b) => Q b -> (Q a -> Q b) -> Q (Maybe a) -> Q b+maybe b f ma = isNothing ma ? (b,f (fromJust ma))++fromMaybe :: (QA a) => Q a -> Q (Maybe a) -> Q a+fromMaybe a ma = isNothing ma ? (a,fromJust ma)++catMaybes :: (QA a) => Q [Maybe a] -> Q [a]+catMaybes = concatMap maybeToList++mapMaybe :: (QA a,QA b) => (Q a -> Q (Maybe b)) -> Q [a] -> Q [b]+mapMaybe f = concatMap (maybeToList . f)++-- * Either++pairToEither :: (QA a,QA b) => Q ([a],[b]) -> Q (Either a b)+pairToEither (Q a) = Q a++eitherToPair :: (QA a,QA b) => Q (Either a b) -> Q ([a],[b])+eitherToPair (Q a) = Q a++left :: (QA a,QA b) => Q a -> Q (Either a b)+left a = pairToEither (tuple (singleton a,nil))++right :: (QA a,QA b) => Q b -> Q (Either a b)+right a = pairToEither (tuple (nil,singleton a))++isLeft :: (QA a,QA b) => Q (Either a b) -> Q Bool+isLeft = null . snd . eitherToPair++isRight :: (QA a,QA b) => Q (Either a b) -> Q Bool+isRight = null . fst . eitherToPair++either :: (QA a,QA b,QA c) => (Q a -> Q c) -> (Q b -> Q c) -> Q (Either a b) -> Q c+either lf rf e = isLeft e ? ((lf . head . fst . eitherToPair) e,(rf . head . snd . eitherToPair) e)++lefts :: (QA a,QA b) => Q [Either a b] -> Q [a]+lefts = concatMap (fst . eitherToPair)++rights :: (QA a,QA b) => Q [Either a b] -> Q [b]+rights = concatMap (snd . eitherToPair)++partitionEithers :: (QA a,QA b) => Q [Either a b] -> Q ([a], [b])+partitionEithers es = tuple (lefts es,rights es)++-- * List Construction++nil :: (QA a) => Q [a]+nil = Q (ListE [])++empty :: (QA a) => Q [a]+empty = nil++cons :: (QA a) => Q a -> Q [a] -> Q [a]+cons (Q a) (Q as) = Q (AppE Cons (PairE a as))++(<|) :: (QA a) => Q a -> Q [a] -> Q [a]+(<|) = cons++snoc :: (QA a) => Q [a] -> Q a -> Q [a]+snoc as a = append as (singleton a)++(|>) :: (QA a) => Q [a] -> Q a -> Q [a]+(|>) = snoc++singleton :: (QA a) => Q a -> Q [a]+singleton (Q e) = cons (Q e) nil++-- * List Operations++head :: (QA a) => Q [a] -> Q a+head (Q as) = Q (AppE Head as)++tail :: (QA a) => Q [a] -> Q [a]+tail (Q as) = Q (AppE Tail as)++take :: (QA a) => Q Integer -> Q [a] -> Q [a]+take (Q i) (Q as) = Q (AppE Take (PairE i as))++drop :: (QA a) => Q Integer -> Q [a] -> Q [a]+drop (Q i) (Q as) = Q (AppE Drop (PairE i as))++map :: (QA a,QA b) => (Q a -> Q b) ->  Q [a] -> Q [b]+map f (Q as) = Q (AppE Map (PairE (LamE (toLam f)) as))++append :: (QA a) => Q [a] -> Q [a] -> Q [a]+append (Q as) (Q bs) = Q (AppE Concat (ListE [as,bs]))++(++) :: (QA a) => Q [a] -> Q [a] -> Q [a]+(++) = append++filter :: (QA a) => (Q a -> Q Bool) -> Q [a] -> Q [a]+filter f (Q as) = Q (AppE Filter (PairE (LamE (toLam f)) as))++groupWith :: (QA a,QA b,Ord b) => (Q a -> Q b) -> Q [a] -> Q [[a]]+groupWith f (Q as) = Q (AppE GroupWith (PairE (LamE (toLam f)) as))++sortWith :: (QA a,QA b,Ord b) => (Q a -> Q b) -> Q [a] -> Q [a]+sortWith f (Q as) = Q (AppE SortWith (PairE (LamE (toLam f)) as))++the :: (QA a,Eq a) => Q [a] -> Q a+the (Q as) = Q (AppE The as)++last :: (QA a) => Q [a] -> Q a+last (Q as) = Q (AppE Last as)++init :: (QA a) => Q [a] -> Q [a]+init (Q as) = Q (AppE Init as)++null :: (QA a) => Q [a] -> Q Bool+null (Q as) = Q (AppE Null as)++length :: (QA a) => Q [a] -> Q Integer+length (Q as) = Q (AppE Length as)++index :: (QA a) => Q [a] -> Q Integer -> Q a+index (Q as) (Q i) = Q (AppE Index (PairE as i))++(!!) :: (QA a) => Q [a] -> Q Integer -> Q a+(!!) = index++reverse :: (QA a) => Q [a] -> Q [a]+reverse (Q as) = Q (AppE Reverse as)++-- * Special folds++and :: Q [Bool] -> Q Bool+and (Q bs) = Q (AppE And bs)++or :: Q [Bool] -> Q Bool+or (Q bs) = Q (AppE Or bs)++any :: (QA a) => (Q a -> Q Bool) -> Q [a] -> Q Bool+any f = or . map f++all :: (QA a) => (Q a -> Q Bool) -> Q [a] -> Q Bool+all f = and . map f++sum :: (QA a,Num a) => Q [a] -> Q a+sum (Q as) = Q (AppE Sum as)++concat :: (QA a) => Q [[a]] -> Q [a]+concat (Q ass) = Q (AppE Concat ass)++concatMap :: (QA a,QA b) => (Q a -> Q [b]) -> Q [a] -> Q [b]+concatMap f as = concat (map f as)++maximum :: (QA a,Ord a) => Q [a] -> Q a+maximum (Q as) = Q (AppE Maximum as)++minimum :: (QA a,Ord a) => Q [a] -> Q a+minimum (Q as) = Q (AppE Minimum as)++-- * Sublists++splitAt :: (QA a) => Q Integer -> Q [a] -> Q ([a],[a])+splitAt (Q i) (Q as) = Q (AppE SplitAt (PairE i as))++takeWhile :: (QA a) => (Q a -> Q Bool) -> Q [a] -> Q [a]+takeWhile f (Q as) = Q (AppE TakeWhile (PairE (LamE (toLam f)) as))++dropWhile :: (QA a) => (Q a -> Q Bool) -> Q [a] -> Q [a]+dropWhile f (Q as) = Q (AppE DropWhile (PairE (LamE (toLam f)) as))++span :: (QA a) => (Q a -> Q Bool) -> Q [a] -> Q ([a],[a])+span f as = pair (takeWhile f as) (dropWhile f as)++break :: (QA a) => (Q a -> Q Bool) -> Q [a] -> Q ([a],[a])+break f = span (not . f)++-- * Searching Lists++elem :: (QA a,Eq a) => Q a -> Q [a] -> Q Bool+elem a as = null (filter (a ==) as) ? (false,true)++notElem :: (QA a,Eq a) => Q a -> Q [a] -> Q Bool+notElem a as = not (a `elem` as)++lookup :: (QA a,QA b,Eq a) => Q a -> Q [(a, b)] -> Q (Maybe b)+lookup a  = listToMaybe . map snd . filter ((a ==) . fst)++-- * Zipping and Unzipping Lists++zip :: (QA a,QA b) => Q [a] -> Q [b] -> Q [(a,b)]+zip (Q as) (Q bs) = Q (AppE Zip (PairE as bs))++zipWith :: (QA a,QA b,QA c) => (Q a -> Q b -> Q c) -> Q [a] -> Q [b] -> Q [c]+zipWith f as bs = map (\e -> f (fst e) (snd e)) (zip as bs)++unzip :: (QA a,QA b) => Q [(a,b)] -> Q ([a],[b])+unzip (Q as) = Q (AppE Unzip as)++-- * Set-oriented operations++nub :: (QA a,Eq a) => Q [a] -> Q [a]+nub (Q as) = Q (AppE Nub as)++-- * Tuple Projection Functions++fst :: (QA a,QA b) => Q (a,b) -> Q a+fst (Q e) = Q (AppE Fst e)++snd :: (QA a,QA b) => Q (a,b) -> Q b+snd (Q e) = Q (AppE Snd e)++pair :: (QA a,QA b) => Q a -> Q b -> Q (a,b)+pair (Q a) (Q b) = Q (PairE a b)++-- * Conversions between numeric types++integerToDouble :: Q Integer -> Q Double+integerToDouble (Q i) = Q (AppE IntegerToDouble i)++-- * Rebind Monadic Combinators++return :: (QA a) => Q a -> Q [a]+return = singleton++(>>=) :: (QA a,QA b) => Q [a] -> (Q a -> Q [b]) -> Q [b]+(>>=) ma f = concatMap f ma++(>>) :: (QA a,QA b) => Q [a] -> Q [b] -> Q [b]+(>>) ma mb = concatMap (\_ -> mb) ma++mzip :: (QA a,QA b) => Q [a] -> Q [b] -> Q [(a,b)]+mzip = zip++guard :: Q Bool -> Q [()]+guard c = cond c (singleton unit) nil++-- * Construction of tuples and records++tuple :: (View a b) => b -> a+tuple = fromView++record :: (View a b) => b -> a+record = fromView++infixl 9  !!+infixr 5  ++, <|, |>+infix  4  ==, /=, <, <=, >=, >+infixr 3  &&+infixr 2  ||+infix  0  ?++deriveTupleRangeQA 3 16++-- * Missing functions++-- $missing+{- $missing++This module offers most of the functions on lists given in PreludeList for the+'Q' type. Missing functions are:++General folds:++> foldl+> foldl1+> scanl+> scanl1+> foldr+> foldr1+> scanr+> scanr1++Infinit lists:++> iterate+> repeat+> cycle++String functions:++> lines+> words+> unlines+> unwords++Zipping and unzipping lists:++> zip3+> zipWith3+> unzip3++-}
src/Database/DSH/Impossible.hs view
@@ -7,4 +7,4 @@   loc <- TH.location   let pos =  (TH.loc_filename loc, fst (TH.loc_start loc), snd (TH.loc_start loc))   let message = "DSH: Impossbile happend at " ++ show pos-  return (TH.AppE (TH.VarE (TH.mkName "error")) (TH.LitE (TH.StringL message)))+  return (TH.AppE (TH.VarE 'error) (TH.LitE (TH.StringL message)))
+ src/Database/DSH/Internals.hs view
@@ -0,0 +1,204 @@+module Database.DSH.Internals where++import Data.Text (Text)++data Exp a where+  UnitE     :: Exp ()+  BoolE     :: Bool    -> Exp Bool+  CharE     :: Char    -> Exp Char+  IntegerE  :: Integer -> Exp Integer+  DoubleE   :: Double  -> Exp Double+  TextE     :: Text    -> Exp Text+  PairE     :: (Reify a, Reify b)  => Exp a -> Exp b -> Exp (a,b)+  ListE     :: (Reify a)           => [Exp a] -> Exp [a]+  AppE      :: (Reify a, Reify b)  => Fun a b -> Exp a -> Exp b+  LamE      :: (Reify a, Reify b)  => (Exp a -> Exp b) -> Exp (a -> b)+  VarE      :: (Reify a)           => Integer -> Exp a+  TableE    :: (Reify a)           => Table -> Exp [a]++data Table = TableDB String [[String]] | TableCSV  String deriving (Eq, Ord, Show)++data Type a where+  UnitT     :: Type ()+  BoolT     :: Type Bool+  CharT     :: Type Char+  IntegerT  :: Type Integer+  DoubleT   :: Type Double+  TextT     :: Type Text+  PairT     :: (Reify a,Reify b)  => Type a -> Type b -> Type (a,b)+  ListT     :: (Reify a)          => Type a -> Type [a]+  ArrowT    :: (Reify a,Reify b)  => Type a -> Type b -> Type (a -> b)++data Fun a b where+    Not             :: Fun Bool Bool+    IntegerToDouble :: Fun Integer Double+    And             :: Fun [Bool] Bool+    Or              :: Fun [Bool] Bool+    Concat          :: (Reify a) => Fun [[a]] [a]+    Head            :: Fun [a] a+    Tail            :: Fun [a] [a]+    The             :: Fun [a] a+    Init            :: Fun [a] [a]+    Last            :: Fun [a] a+    Null            :: Fun [a] Bool+    Length          :: Fun [a] Integer+    Reverse         :: Fun [a] [a]+    Fst             :: Fun (a,b) a+    Snd             :: Fun (a,b) b+    Sum             :: Fun [a] a+    Maximum         :: Fun [a] a+    Minimum         :: Fun [a] a+    Unzip           :: (Reify a,Reify b) => Fun [(a,b)] ([a],[b])+    Nub             :: Fun [a] [a]+    Add             :: Fun (a,a) a+    Mul             :: Fun (a,a) a+    Sub             :: Fun (a,a) a+    Div             :: Fun (a,a) a+    Lt              :: Fun (a,a) Bool+    Lte             :: Fun (a,a) Bool+    Equ             :: Fun (a,a) Bool+    Gte             :: Fun (a,a) Bool+    Gt              :: Fun (a,a) Bool+    Conj            :: Fun (Bool,Bool) Bool+    Disj            :: Fun (Bool,Bool) Bool+    Min             :: Fun (a,a) a+    Max             :: Fun (a,a) a+    Cons            :: Fun (a,[a]) [a]+    Take            :: Fun (Integer,[a]) [a]+    Drop            :: Fun (Integer,[a]) [a]+    Index           :: Fun ([a],Integer) a+    SplitAt         :: Fun (Integer,[a]) ([a],[a])+    Zip             :: Fun ([a],[b]) [(a,b)]+    Map             :: Fun (a -> b,[a]) [b]+    Filter          :: Fun (a -> Bool,[a]) [a]+    GroupWith       :: (Reify b) => Fun (a -> b,[a]) [[a]]+    SortWith        :: Fun (a -> b,[a]) [a]+    TakeWhile       :: Fun (a -> Bool,[a]) [a]+    DropWhile       :: Fun (a -> Bool,[a]) [a]+    Cond            :: Fun (Bool,(a,a)) a++data Q a where+  Q :: Exp (Rep a) -> Q a++-- Classes++class Reify a where+  reify :: a -> Type a++class (Reify (Rep a)) => QA a where+  type Rep a+  toExp :: a -> Exp (Rep a)+  frExp :: Exp (Rep a) -> a++class (QA a,QA r) => Elim a r where+  type Eliminator a r+  elim :: Q a -> Eliminator a r++class BasicType a where++class TA a where++class (ToView a ~ b, FromView b ~ a) => View a b where+  type ToView a+  type FromView b+  view :: a -> b+  fromView :: b -> a++-- Show instances++instance Show (Type a) where+  show UnitT = "()"+  show BoolT = "Bool"+  show CharT = "Char"+  show IntegerT = "Integer"+  show DoubleT = "Double"+  show TextT = "Text"+  show (PairT l r) = "(" ++ show l ++ ", " ++ show r ++ ")"+  show (ListT t) = "[" ++ show t ++ "]"+  show (ArrowT t1 t2) = "(" ++ show t1 ++ " -> " ++ show t2 ++ ")"++instance Show (Fun a b) where+    show Fst = "fst"+    show Snd = "snd"+    show Not = "not"+    show Concat = "concat"+    show Head = "head"+    show Tail = "tail"+    show The = "the"+    show Init = "init"+    show Last = "last"+    show Null = "null"+    show Length = "length"+    show Reverse = "reverse"+    show And = "and"+    show Or = "or"+    show Sum = "sum"+    show Maximum = "maximum"+    show Minimum = "minimum"+    show Unzip = "unzip"+    show Nub = "nub"+    show IntegerToDouble = "integerToDouble"+    show Add = "+"+    show Mul = "*"+    show Sub = "-"+    show Div = "/"+    show Lt  = "<"+    show Lte = "<="+    show Equ = "=="+    show Gte = ">="+    show Gt  = ">"+    show Conj = "&&"+    show Disj = "||"+    show Min  = "min"+    show Max  = "max"+    show Cons = "cons"+    show Take = "take"+    show Drop = "drop"+    show Index = "index"+    show SplitAt = "splitAt"+    show Zip = "zip"+    show Map = "map"+    show Filter = "filter"+    show GroupWith = "groupWith"+    show SortWith = "sortWith"+    show TakeWhile = "takeWhile"+    show DropWhile = "dropWhile"+    show Cond = "cond"++-- Reify instances++instance Reify () where+  reify _ = UnitT++instance Reify Bool where+  reify _ = BoolT++instance Reify Char where+  reify _ = CharT++instance Reify Integer where+  reify _ = IntegerT++instance Reify Double where+  reify _ = DoubleT++instance Reify Text where+  reify _ = TextT++instance (Reify a, Reify b) => Reify (a,b) where+  reify _ = PairT (reify (undefined :: a)) (reify (undefined :: b))++instance (Reify a) => Reify [a] where+  reify _ = ListT (reify (undefined :: a))++instance (Reify a, Reify b) => Reify (a -> b) where+  reify _ = ArrowT (reify (undefined :: a)) (reify (undefined :: b))+++-- Utility functions++unQ :: Q a -> Exp (Rep a)+unQ (Q e) = e++toLam :: (QA a,QA b) => (Q a -> Q b) -> Exp (Rep a) -> Exp (Rep b)+toLam f = unQ . f . Q
src/Database/DSH/Interpreter.hs view
@@ -1,394 +1,385 @@ -- | This module provides the reference implementation of DSH by interpreting -- the embedded representation. -{-# LANGUAGE TemplateHaskell, ViewPatterns, ScopedTypeVariables #-}-{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}- module Database.DSH.Interpreter (fromQ) where -import Database.DSH.Data-import Database.DSH.Impossible (impossible)-import Database.DSH.CSV (csvImport)+import Database.DSH.Internals+import Database.DSH.Impossible+import Database.DSH.CSV -import Data.Convertible+import qualified Data.Text as T+import qualified Data.Text.Encoding as T import Database.HDBC-import GHC.Exts import Data.List  fromQ :: (QA a, IConnection conn) => conn -> Q a -> IO a-fromQ c (Q a) = evaluate c a >>= (return . fromNorm)+fromQ c (Q e) = fmap frExp (evaluate c e) -evaluate :: IConnection conn-         => conn                -- ^ The HDBC connection-         -> Exp-         -> IO Norm+evaluate :: forall a conn. (Reify a, IConnection conn) => conn -> Exp a -> IO (Exp a) evaluate c e = case e of-  UnitE t      -> return (UnitN t)-  BoolE b t    -> return (BoolN b t)-  CharE ch t   -> return (CharN ch t)-  IntegerE i t -> return (IntegerN i t)-  DoubleE d t  -> return (DoubleN d t)-  TextE s t    -> return (TextN s t)--  VarE _ _ -> $impossible-  LamE _ _ -> $impossible--  TupleE e1 e2 t -> do-    e3 <- evaluate c e1-    e4 <- evaluate c e2-    return (TupleN e3 e4 t)--  ListE es t -> do-      es1 <- mapM (evaluate c) es-      return (ListN es1 t)--  AppE3 Cond cond a b _ -> do-      (BoolN c1 _) <- evaluate c cond+    UnitE -> return UnitE+    BoolE b -> return $ BoolE b+    CharE ch -> return $ CharE ch+    IntegerE i -> return $ IntegerE i+    DoubleE d -> return $ DoubleE d+    TextE t -> return $ TextE t +    VarE _ -> $impossible+    LamE _ -> $impossible+    PairE e1 e2 -> do+      e1' <- evaluate c e1+      e2' <- evaluate c e2+      return (PairE e1' e2')+    ListE es -> do+       es1 <- mapM (evaluate c) es+       return $ ListE es1 +    AppE Cond (PairE cond (PairE a b)) -> do+      (BoolE c1) <- evaluate c cond       if c1 then evaluate c a else evaluate c b--  AppE2 Cons a as t -> do-    a1 <- evaluate c a-    (ListN as1 _) <- evaluate c as-    return $ ListN (a1 : as1) t--  AppE2 Snoc as a t -> do-    a1 <- evaluate c a-    (ListN as1 _) <- evaluate c as-    return $ ListN (snoc as1 a1) t--  AppE1 Head as _ -> do-    (ListN as1 _) <- evaluate c as-    return $ head as1--  AppE1 Tail as t -> do-    (ListN as1 _) <- evaluate c as-    return $ ListN (tail as1) t--  AppE2 Take i as t -> do-    (IntegerN i1 _) <- evaluate c i-    (ListN as1 _) <- evaluate c as-    return $ ListN (take (fromIntegral i1) as1) t--  AppE2 Drop i as t -> do-    (IntegerN i1 _) <- evaluate c i-    (ListN as1 _) <- evaluate c as-    return $ ListN (drop (fromIntegral i1) as1) t--  AppE2 Map lam as t -> do-    (ListN as1 _) <- evaluate c as-    evaluate c $ ListE (map (evalLam lam) as1) t--  AppE2 Append as bs t -> do-    (ListN as1 _) <- evaluate c as-    (ListN bs1 _) <- evaluate c bs-    return $ ListN (as1 ++ bs1) t--  AppE2 Filter lam as t -> do-    (ListN as1 _) <- evaluate c as-    (ListN as2 _) <- evaluate c (ListE (map (evalLam lam) as1) (ListT BoolT))-    return $ ListN (map fst (filter (\(_,(BoolN b BoolT)) -> b) (zip as1 as2))) t--  AppE2 GroupWith lam as t -> do-    (ListN as1 t1) <- evaluate c as-    (ListN as2 _ ) <- evaluate c (ListE (map (evalLam lam) as1) (ListT (typeArrowResult (typeExp lam))))-    return $ ListN (map ((flip ListN) t1 . (map fst)) $ groupWith snd $ zip as1 as2) t--  AppE2 SortWith lam as t -> do-    (ListN as1 _) <- evaluate c as-    (ListN as2 _) <- evaluate c (ListE (map (evalLam lam) as1) (ListT (typeArrowResult (typeExp lam))))-    return $ ListN (map fst $ sortWith snd $ zip as1 as2) t--  AppE2 Max e1 e2 IntegerT -> do-     (IntegerN v1 _) <- evaluate c e1-     (IntegerN v2 _) <- evaluate c e2-     return $ IntegerN (max v1 v2) IntegerT--  AppE2 Max e1 e2 DoubleT -> do-     (DoubleN v1 _) <- evaluate c e1-     (DoubleN v2 _) <- evaluate c e2-     return $ DoubleN (max v1 v2) DoubleT--  AppE2 Min e1 e2 IntegerT -> do-     (IntegerN v1 _) <- evaluate c e1-     (IntegerN v2 _) <- evaluate c e2-     return $ IntegerN (min v1 v2) IntegerT--  AppE2 Min e1 e2 DoubleT -> do-     (DoubleN v1 _) <- evaluate c e1-     (DoubleN v2 _) <- evaluate c e2-     return $ DoubleN (min v1 v2) DoubleT--  AppE1 The as _ -> do-    (ListN as1 _) <- evaluate c as-    return $ the as1--  AppE1 Last as _ -> do-    (ListN as1 _) <- evaluate c as-    return $ last as1--  AppE1 Init as t -> do-    (ListN as1 _) <- evaluate c as-    return $ ListN (init as1) t--  AppE1 Null as _ -> do-    (ListN as1 _) <- evaluate c as-    return $ BoolN (null as1) BoolT--  AppE1 Length as _ -> do-    (ListN as1 _) <- evaluate c as-    return $ IntegerN (fromIntegral $ length as1) IntegerT--  AppE2 Index as i _ -> do-    (IntegerN i1 _) <- evaluate c i-    (ListN as1 _) <- evaluate c as-    return $ as1 !! (fromIntegral i1)--  AppE1 Reverse as t -> do-    (ListN as1 _) <- evaluate c as-    return $ ListN (reverse as1) t--  AppE1 And as _ -> do-    (ListN as1 _) <- evaluate c as-    return $ BoolN (and $ map (\(BoolN b BoolT) -> b) as1) BoolT--  AppE1 Or as _ -> do-    (ListN as1 _) <- evaluate c as-    return $ BoolN (or $ map (\(BoolN b BoolT) -> b) as1) BoolT--  AppE2 Any lam as _ -> do-    (ListN as1 _) <- evaluate c as-    (ListN as2 _) <- evaluate c (ListE (map (evalLam lam) as1) (typeArrowResult (typeExp lam)))-    return $ BoolN (any id $ map (\(BoolN b BoolT) -> b) as2) BoolT--  AppE2 All lam as _ -> do-    (ListN as1 _) <- evaluate c as-    (ListN as2 _) <- evaluate c (ListE (map (evalLam lam) as1) (typeArrowResult (typeExp lam)))-    return $ BoolN (all id $ map (\(BoolN b BoolT) -> b) as2) BoolT--  AppE1 Sum as IntegerT -> do-    (ListN as1 _) <- evaluate c as-    return $ IntegerN (sum $ map (\(IntegerN i IntegerT) -> i) as1) IntegerT--  AppE1 Sum as DoubleT -> do-    (ListN as1 _) <- evaluate c as-    return $ DoubleN (sum $ map (\(DoubleN d DoubleT) -> d) as1) DoubleT--  AppE1 Sum _ _ -> $impossible--  AppE1 Concat as t -> do-    (ListN as1 _) <- evaluate c as-    return $ ListN (concat $ map (\(ListN as2 _) -> as2) as1) t--  AppE1 Maximum as _ -> do-    (ListN as1 _) <- evaluate c as-    return $ maximum as1--  AppE1 Minimum as _ -> do-    (ListN as1 _) <- evaluate c as-    return $ minimum as1--  AppE2 SplitAt i as t -> do-    (IntegerN i1 _) <- evaluate c i-    (ListN as1 t1) <- evaluate c as-    let r = splitAt (fromIntegral i1) as1-    return $ TupleN (ListN (fst r) t1) (ListN (snd r) t1) t--  AppE2 TakeWhile lam as t -> do-    (ListN as1 _) <- evaluate c as-    (ListN as2 _) <- evaluate c (ListE (map (evalLam lam) as1) (typeArrowResult (typeExp lam)))-    return $ ListN (map fst $ takeWhile (\(_,BoolN b BoolT) -> b) $ zip as1 as2) t--  AppE2 DropWhile lam as t -> do-    (ListN as1 _) <- evaluate c as-    (ListN as2 _) <- evaluate c (ListE (map (evalLam lam) as1) (typeArrowResult (typeExp lam)))-    return $ ListN (map fst $ dropWhile (\(_,BoolN b BoolT) -> b) $ zip as1 as2) t--  AppE2 Span lam as t -> do-    (ListN as1 t1) <- evaluate c as-    (ListN as2 _) <- evaluate c (ListE (map (evalLam lam) as1) (typeArrowResult (typeExp lam)))-    return $ (\(a,b) -> TupleN a b t)-           $ (\(a,b) -> (ListN (map fst a) t1, ListN (map fst b) t1))-           $ span (\(_,BoolN b BoolT) -> b)-           $ zip as1 as2--  AppE2 Break lam as t -> do-    (ListN as1 t1) <- evaluate c as-    (ListN as2 _) <- evaluate c (ListE (map (evalLam lam) as1) (typeArrowResult (typeExp lam)))-    return $ (\(a,b) -> TupleN a b t)-           $ (\(a,b) -> (ListN (map fst a) t1, ListN (map fst b) t1))-           $ break (\(_,BoolN b BoolT) -> b)-           $ zip as1 as2--  AppE2 Zip as bs t -> do-    (ListN as1 (ListT t1)) <- evaluate c as-    (ListN bs1 (ListT t2)) <- evaluate c bs-    return $ ListN (zipWith (\a b -> TupleN a b (TupleT t1 t2)) as1 bs1) t--  AppE1 Unzip as t -> do-    (ListN as1 (ListT (TupleT t1 t2))) <- evaluate c as-    return $ TupleN (ListN (map (\(TupleN a _ _) -> a) as1) (ListT t1))-                    (ListN (map (\(TupleN _ b _) -> b) as1) (ListT t2))-                    t--  AppE3 ZipWith lam as bs t -> do-    (ListN as1 _) <- evaluate c as-    (ListN bs1 _) <- evaluate c bs-    evaluate c $ ListE (zipWith (\a b -> let lam1 = ((evalLam lam) a) in (evalLam lam1) b) as1 bs1) t--  AppE1 Nub as t -> do-    (ListN as1 _) <- evaluate c as-    return $ ListN (nub as1) t--  AppE1 Fst a _ -> do-    (TupleN a1 _ _) <- evaluate c a-    return a1--  AppE1 Snd a _ -> do-    (TupleN _ a1 _) <- evaluate c a-    return a1--  AppE2 Add e1 e2 IntegerT -> do-    (IntegerN i1 _) <- evaluate c e1-    (IntegerN i2 _) <- evaluate c e2-    return $ IntegerN (i1 + i2) IntegerT-  AppE2 Add e1 e2 DoubleT -> do-    (DoubleN d1 _) <- evaluate c e1-    (DoubleN d2 _) <- evaluate c e2-    return $ DoubleN (d1 + d2) DoubleT-  AppE2 Add _ _ _ -> $impossible--  AppE2 Sub e1 e2 IntegerT -> do-    (IntegerN i1 _) <- evaluate c e1-    (IntegerN i2 _) <- evaluate c e2-    return $ IntegerN (i1 - i2) IntegerT-  AppE2 Sub e1 e2 DoubleT -> do-    (DoubleN d1 _) <- evaluate c e1-    (DoubleN d2 _) <- evaluate c e2-    return $ DoubleN (d1 - d2) DoubleT-  AppE2 Sub _ _ _ -> $impossible--  AppE2 Mul e1 e2 IntegerT -> do-    (IntegerN i1 _) <- evaluate c e1-    (IntegerN i2 _) <- evaluate c e2-    return $ IntegerN (i1 * i2) IntegerT-  AppE2 Mul e1 e2 DoubleT -> do-    (DoubleN d1 _) <- evaluate c e1-    (DoubleN d2 _) <- evaluate c e2-    return $ DoubleN (d1 * d2) DoubleT-  AppE2 Mul _ _ _ -> $impossible-  -  AppE2 Div e1 e2 DoubleT -> do-    (DoubleN d1 _) <- evaluate c e1-    (DoubleN d2 _) <- evaluate c e2-    return $ DoubleN (d1 / d2) DoubleT-  AppE2 Div _ _ _ -> $impossible-  -  AppE1 IntegerToDouble e1 DoubleT -> do-    (IntegerN i1 _) <- evaluate c e1-    return $ DoubleN (fromInteger i1) DoubleT-    -  AppE1 IntegerToDouble _ _ -> $impossible--  AppE2 Equ e1 e2 _ -> do-    e3 <- evaluate c e1-    e4 <- evaluate c e2-    return $ BoolN (e3 == e4) BoolT--  AppE2 Lt e1 e2 _ -> do-    e3 <- evaluate c e1-    e4 <- evaluate c e2-    return $ BoolN (e3 < e4) BoolT--  AppE2 Lte e1 e2 _ -> do-    e3 <- evaluate c e1-    e4 <- evaluate c e2-    return $ BoolN (e3 <= e4) BoolT--  AppE2 Gte e1 e2 _ -> do-    e3 <- evaluate c e1-    e4 <- evaluate c e2-    return $ BoolN (e3 >= e4) BoolT--  AppE2 Gt e1 e2 _ -> do-    e3 <- evaluate c e1-    e4 <- evaluate c e2-    return $ BoolN (e3 > e4) BoolT+    AppE Cons (PairE a as) -> do+      a1 <- evaluate c a+      (ListE as1) <- evaluate c as+      return $ ListE (a1 : as1)+    AppE Head as -> do+      (ListE as1) <- evaluate c as+      return $ head as1+    AppE Tail as -> do+      (ListE as1) <- evaluate c as+      return $ ListE (tail as1)+    AppE Take (PairE i as) -> do+      (IntegerE i1) <- evaluate c i+      (ListE as1) <- evaluate c as+      return $ ListE (take (fromIntegral i1) as1)+    AppE Drop (PairE i as) -> do+      (IntegerE i1) <- evaluate c i+      (ListE as1) <- evaluate c as+      return $ ListE (drop (fromIntegral i1) as1)+    AppE Map (PairE (LamE f) as) -> do+      (ListE as1) <- evaluate c as+      evaluate c $ ListE (map f as1)+    AppE Filter (PairE (LamE f) as) -> do+      (ListE as1) <- evaluate c as+      (ListE as2) <- evaluate c (ListE (map f as1))+      return $ ListE (map fst (filter (\(_,BoolE b) -> b) (zip as1 as2))) +    AppE GroupWith (PairE (LamE f) as) -> do+      (ListE as1) <- evaluate c as+      (ListE as2) <- evaluate c (ListE (map f as1))+      return $ ListE+             $ map (ListE . map fst)+             $ groupBy (\(_,a1) (_,a2) -> equExp a1 a2)+             $ sortBy (\(_,a1) (_,a2) -> compareExp a1 a2)+             $ zip as1 as2+    AppE SortWith (PairE (LamE f) as) -> do+      (ListE as1) <- evaluate c as+      (ListE as2) <- evaluate c $ ListE (map f as1) +      return $ ListE +             $ map fst+             $ sortBy (\(_,a1) (_,a2) -> compareExp a1 a2)+             $ zip as1 as2+    (AppE Max (PairE e1 e2)) ->+      case reify (undefined :: a) of+          IntegerT -> do+                        (IntegerE v1) <- evaluate c e1+                        (IntegerE v2) <- evaluate c e2+                        return $ IntegerE (max v1 v2)+          DoubleT -> do +                        (DoubleE v1) <- evaluate c e1+                        (DoubleE v2) <- evaluate c e2+                        return $ DoubleE (max v1 v2)+          _ -> $impossible+    (AppE Min (PairE e1 e2)) ->+      case reify (undefined :: a) of+          IntegerT -> do+                        (IntegerE v1) <- evaluate c e1+                        (IntegerE v2) <- evaluate c e2+                        return $ IntegerE (min v1 v2)+          DoubleT -> do+                        (DoubleE v1) <- evaluate c e1+                        (DoubleE v2) <- evaluate c e2+                        return $ DoubleE (min v1 v2)+          _ -> $impossible+    AppE The as -> do+      (ListE as1) <- evaluate c as+      case as1 of+        [] -> error "Database.DSH.Interpreter.the: empty list"+        (x : xs) -> return $ if all (equExp x) xs+                                then x+                                else error "Database.DSH.Interpreter.the: non-identical elements"+    AppE Last as -> do+      (ListE as1) <- evaluate c as+      return $ last as1+    AppE Init as -> do+      (ListE as1) <- evaluate c as+      return $ ListE (init as1)+    AppE Null as -> do+      (ListE as1) <- evaluate c as+      return $ BoolE (null as1)+    AppE Length as -> do+     (ListE as1) <- evaluate c as+     return $ IntegerE (fromIntegral $ length as1)+    AppE Index (PairE as i) -> do+     (IntegerE i1) <- evaluate c i+     (ListE as1) <- evaluate c as+     return $ as1 !! fromIntegral i1+    AppE Reverse as -> do+      (ListE as1) <- evaluate c as+      return $ ListE (reverse as1)+    AppE And as -> do+      (ListE as1) <- evaluate c as+      return $ BoolE (all (\(BoolE b) -> b) as1)+    AppE Or as -> do+      (ListE as1) <- evaluate c as+      return $ BoolE (any (\(BoolE b) -> b) as1)+    (AppE Sum as) -> do+      let ty = reify (undefined :: a)+      (ListE as1) <- evaluate c as+      case ty of+          IntegerT -> return $ IntegerE (sum $ map (\(IntegerE i) -> i) as1)+          DoubleT  -> return $ DoubleE (sum $ map (\(DoubleE d) -> d) as1)+          _ -> $impossible+    AppE Concat as -> do+      (ListE as1) <- evaluate c as+      return $ ListE (concatMap (\(ListE as2) -> as2) as1)+    AppE Maximum as -> do+      (ListE as1) <- evaluate c as+      return $ maximumBy compareExp as1+    AppE Minimum as -> do+      (ListE as1) <- evaluate c as+      return $ minimumBy compareExp as1+    AppE SplitAt (PairE i as) -> do+      (IntegerE i1) <- evaluate c i+      (ListE as1) <- evaluate c as+      let r = splitAt (fromIntegral i1) as1+      return $ PairE (ListE (fst r)) (ListE (snd r)) +    AppE TakeWhile (PairE (LamE f) as) -> do+      (ListE as1) <- evaluate c as+      (ListE as2) <- evaluate c (ListE (map f as1))+      return $ ListE (map fst $ takeWhile (\(_,BoolE b) -> b) $ zip as1 as2)+    AppE DropWhile (PairE (LamE f) as) -> do+      (ListE as1) <- evaluate c as+      (ListE as2) <- evaluate c (ListE (map f as1))+      return $ ListE (map fst $ dropWhile (\(_,BoolE b) -> b) $ zip as1 as2)+    AppE Zip (PairE as bs) -> do+      (ListE as1) <- evaluate c as+      (ListE bs1) <- evaluate c bs+      return $ ListE (zipWith PairE as1 bs1)+    AppE Unzip as -> do+      (ListE as1) <- evaluate c as+      return $ PairE (ListE (map (\(PairE a _) -> a) as1)) (ListE (map (\(PairE _ b) -> b) as1))+    AppE Nub as -> do+      (ListE as1) <- evaluate c as+      return $ ListE (nubBy equExp as1)+    AppE Fst a -> do+      (PairE a1 _) <- evaluate c a+      return a1+    AppE Snd a -> do+      (PairE _ a1) <- evaluate c a+      return a1+    (AppE Add (PairE e1 e2)) -> do+      let ty = reify (undefined :: a)+      case ty of+         IntegerT -> do+                      (IntegerE i1) <- evaluate c e1+                      (IntegerE i2) <- evaluate c e2+                      return $ IntegerE (i1 + i2)+         DoubleT  -> do+                      (DoubleE d1) <- evaluate c e1+                      (DoubleE d2) <- evaluate c e2+                      return $ DoubleE (d1 + d2)+         _ -> $impossible+    (AppE Sub (PairE e1 e2)) -> do+      let ty = reify (undefined :: a)+      case ty of+         IntegerT -> do+                      (IntegerE i1) <- evaluate c e1+                      (IntegerE i2) <- evaluate c e2+                      return $ IntegerE (i1 - i2)+         DoubleT  -> do+                      (DoubleE d1) <- evaluate c e1+                      (DoubleE d2) <- evaluate c e2+                      return $ DoubleE (d1 - d2)+         _ -> $impossible+    (AppE Mul (PairE e1 e2)) -> do+      let ty = reify (undefined :: a)+      case ty of+         IntegerT -> do+                      (IntegerE i1) <- evaluate c e1+                      (IntegerE i2) <- evaluate c e2+                      return $ IntegerE (i1 * i2)+         DoubleT  -> do+                      (DoubleE d1) <- evaluate c e1+                      (DoubleE d2) <- evaluate c e2+                      return $ DoubleE (d1 * d2)+         _ -> $impossible+    (AppE Div (PairE e1 e2)) -> do+      let ty = reify (undefined :: a)+      case ty of+         DoubleT  -> do+                      (DoubleE d1) <- evaluate c e1+                      (DoubleE d2) <- evaluate c e2+                      return $ DoubleE (d1 / d2)+         _ -> $impossible+    AppE IntegerToDouble e1 -> do+      (IntegerE i1) <- evaluate c e1+      return $ DoubleE (fromInteger i1)+    AppE Equ (PairE e1 e2) -> do+      e3 <- evaluate c e1+      e4 <- evaluate c e2+      return $ BoolE $ equExp e3 e4+    AppE Lt (PairE e1 e2) -> do+      e3 <- evaluate c e1+      e4 <- evaluate c e2+      return $ BoolE $ ltExp e3 e4+    AppE Lte (PairE e1 e2) -> do+      e3 <- evaluate c e1+      e4 <- evaluate c e2+      return $ BoolE $ lteExp e3 e4+    AppE Gte (PairE e1 e2) -> do+      e3 <- evaluate c e1+      e4 <- evaluate c e2+      return $ BoolE $ gteExp e3 e4+    AppE Gt (PairE e1 e2) -> do+      e3 <- evaluate c e1+      e4 <- evaluate c e2+      return $ BoolE $ gtExp e3 e4+    AppE Not e1 -> do+      (BoolE b1) <- evaluate c e1+      return $ BoolE (not b1)+    AppE Conj (PairE e1 e2) -> do+      (BoolE b1) <- evaluate c e1+      (BoolE b2) <- evaluate c e2+      return $ BoolE (b1 && b2)+    AppE Disj (PairE e1 e2) -> do+      (BoolE b1) <- evaluate c e1+      (BoolE b2) <- evaluate c e2+      return $ BoolE (b1 || b2) +    (TableE (TableDB tName _)) -> +      let ty = reify (undefined :: a)+      in case ty of+          ListT tType -> do+            tDesc <- describeTable c (escape tName)+            let columnNames = intercalate " , " $ map (\s -> "\"" ++ s ++ "\"") $ sort $ map fst tDesc+            let query = "SELECT " ++ columnNames ++ " FROM " ++ "\"" ++ escape tName ++ "\""+            -- print query+            fmap (sqlToExpWithType (escape tName) tType) (quickQuery c query [])+          _ -> $impossible+    (TableE (TableCSV filename)) -> csvImport filename (reify (undefined :: a))+    _ -> $impossible -  AppE1 Not e1 _ -> do-    (BoolN b1 _) <- evaluate c e1-    return $ BoolN (not b1) BoolT+compareExp :: Exp a -> Exp a -> Ordering+compareExp UnitE UnitE                       = EQ+compareExp (BoolE v1) (BoolE v2)             = compare v1 v2+compareExp (CharE v1) (CharE v2)             = compare v1 v2+compareExp (IntegerE v1) (IntegerE v2)       = compare v1 v2+compareExp (DoubleE v1) (DoubleE v2)         = compare v1 v2+compareExp (TextE v1) (TextE v2)             = compare v1 v2+compareExp (PairE a1 b1) (PairE a2 b2)       = case compareExp a1 a2 of+                                                 EQ -> compareExp b1 b2+                                                 LT -> LT+                                                 GT -> GT+compareExp (ListE []) (ListE [])             = EQ+compareExp (ListE (_ : _)) (ListE [])        = GT+compareExp (ListE []) (ListE (_ : _))        = LT+compareExp (ListE (a : as)) (ListE (b : bs)) = case compareExp a b of+                                                 EQ -> compareExp (ListE as) (ListE bs)+                                                 LT -> LT+                                                 GT -> GT+compareExp _ _ = $impossible -  AppE2 Conj e1 e2 _ -> do-    (BoolN b1 _) <- evaluate c e1-    (BoolN b2 _) <- evaluate c e2-    return $ BoolN (b1 && b2) BoolT+equExp :: Exp a -> Exp a -> Bool+equExp a b = case compareExp a b of+              EQ -> True+              _  -> False -  AppE2 Disj e1 e2 _ -> do-    (BoolN b1 _) <- evaluate c e1-    (BoolN b2 _) <- evaluate c e2-    return $ BoolN (b1 || b2) BoolT+ltExp :: Exp a -> Exp a -> Bool+ltExp a b = case compareExp a b of+              LT -> True+              _  -> False -  TableE (TableDB (escape -> tName) _) (ListT tType) -> do-      tDesc <- describeTable c tName-      let columnNames = concat $ intersperse " , " $ map (\s -> "\"" ++ s ++ "\"") $ sort $ map fst tDesc-      let query = "SELECT " ++ columnNames ++ " FROM " ++ "\"" ++ tName ++ "\""-      print query-      fmap (sqlToNormWithType tName tType) (quickQuery c query [])-  TableE (TableCSV filename) t -> csvImport filename t-  TableE _ _ -> $impossible+lteExp :: Exp a -> Exp a -> Bool+lteExp a b = case compareExp a b of+               GT -> False+               _  -> True +gteExp :: Exp a -> Exp a -> Bool+gteExp a b = case compareExp a b of+               LT -> False+               _  -> True -snoc :: [a] -> a -> [a]-snoc [] a = [a]-snoc (b : bs) a = b : snoc bs a+gtExp :: Exp a -> Exp a -> Bool+gtExp a b = case compareExp a b of+               GT -> True+               _  -> False  escape :: String -> String escape []                  = [] escape (c : cs) | c == '"' = '\\' : '"' : escape cs escape (c : cs)            =          c : escape cs -evalLam :: Exp -> (Norm -> Exp)-evalLam (LamE f _) n = f (convert n)-evalLam _ _ = $impossible-- -- | Read SQL values into 'Norm' values-sqlToNormWithType :: String             -- ^ Table name, used to generate more-                                        -- informative error messages-                  -> Type-                  -> [[SqlValue]]-                  -> Norm-sqlToNormWithType tName ty = (flip ListN) (ListT ty) . map (sqlValueToNorm ty)-+sqlToExpWithType :: (Reify a)+                 => String  -- ^ Table name, used to generate more informative error messages+                 -> Type a+                 -> [[SqlValue]]+                 -> Exp [a]+sqlToExpWithType tName ty = ListE . map (sqlValueToNorm ty)   where-    sqlValueToNorm :: Type -> [SqlValue] -> Norm-+    sqlValueToNorm :: Type a -> [SqlValue] -> Exp a+    sqlValueToNorm (PairT t1 t2) s = let v1 = sqlValueToNorm t1 $ take (sizeOfType t1) s+                                         v2 = sqlValueToNorm t2 $ drop (sizeOfType t1) s+                                      in PairE v1 v2     -- On a single value, just compare the 'Type' and convert the 'SqlValue' to     -- a Norm value on match     sqlValueToNorm t [s] = if t `typeMatch` s-                      then convert s+                      then convert s t                       else typeError t [s]--    -- On more than one value we need a 'TupleT' type of the exact same length-    sqlValueToNorm t s | length (unfoldType t) == length s =-            let f t' s' = if t' `typeMatch` s'-                             then convert s'-                             else typeError t s-            in foldr1 (\a b -> TupleN a b (TupleT (typeNorm a) (typeNorm b)))-                      (zipWith f (unfoldType t) s)-     -- Everything else will raise an error     sqlValueToNorm t s = typeError t s -    typeError :: Type -> [SqlValue] -> a+    typeError :: Type a -> [SqlValue] -> b     typeError t s = error $         "ferry: Type mismatch on table \"" ++ tName ++ "\":"         ++ "\n\tExpected table type: " ++ show t         ++ "\n\tTable entry: " ++ show s +convert :: SqlValue -> Type a -> Exp a+convert SqlNull         UnitT    = UnitE+convert (SqlInteger i)  IntegerT = IntegerE i+convert (SqlInt32 i)    IntegerT = IntegerE $ fromIntegral i+convert (SqlInt64 i)    IntegerT = IntegerE $ fromIntegral i+convert (SqlWord32 i)   IntegerT = IntegerE $ fromIntegral i+convert (SqlWord64 i)   IntegerT = IntegerE $ fromIntegral i+convert (SqlDouble d)  DoubleT  = DoubleE d+convert (SqlRational d) DoubleT = DoubleE $ fromRational d+convert (SqlInteger d)  DoubleT = DoubleE $ fromIntegral d+convert (SqlInt32 d)    DoubleT = DoubleE $ fromIntegral d+convert (SqlInt64 d)    DoubleT = DoubleE $ fromIntegral d+convert (SqlWord32 d)   DoubleT = DoubleE $ fromIntegral d+convert (SqlWord64 d)   DoubleT = DoubleE $ fromIntegral d+convert (SqlBool b) BoolT       = BoolE b+convert (SqlInteger i) BoolT    = BoolE (i /= 0)+convert (SqlInt32 i)   BoolT    = BoolE (i /= 0)+convert (SqlInt64 i)   BoolT    = BoolE (i /= 0)+convert (SqlWord32 i)  BoolT    = BoolE (i /= 0)+convert (SqlWord64 i)  BoolT    = BoolE (i /= 0) +convert (SqlChar c) CharT       = CharE c+convert (SqlString (c:_)) CharT = CharE c+convert (SqlByteString c) CharT = CharE (head $ T.unpack $ T.decodeUtf8 c)+convert (SqlString t) TextT     = TextE (T.pack t) +convert (SqlByteString s) TextT = TextE (T.decodeUtf8 s)+convert sql                 _   = error $ "Unsupported SqlValue: "  ++ show sql +sizeOfType :: Type a -> Int+sizeOfType UnitT = 1+sizeOfType IntegerT = 1+sizeOfType DoubleT = 1+sizeOfType BoolT = 1+sizeOfType CharT = 1+sizeOfType TextT = 1+sizeOfType (PairT t1 t2) = sizeOfType t1 + sizeOfType t2+sizeOfType _ = error "sizeOfType: Not a record type"+ -- | Check if a 'SqlValue' matches a 'Type'-typeMatch :: Type -> SqlValue -> Bool+typeMatch :: Type a -> SqlValue -> Bool typeMatch t s =     case (t,s) of          (UnitT         , SqlNull)          -> True
− src/Database/DSH/JSON.hs
@@ -1,33 +0,0 @@-module Database.DSH.JSON (jsonExport, jsonExportHandle, jsonExportStdout) where--import Database.DSH.Data--import Text.JSON--import qualified Data.Text as Text--import qualified System.IO as IO-import System.IO (Handle)--jsonExport :: (QA a) => FilePath -> [a] -> IO ()-jsonExport file as = IO.withFile file IO.WriteMode (\handle -> jsonExportHandle handle as)--jsonExportStdout :: (QA a) => [a] -> IO ()-jsonExportStdout = jsonExportHandle IO.stdout--jsonExportHandle :: (QA a) => Handle -> [a] -> IO ()-jsonExportHandle handle as = IO.hPutStr handle (encode $ go $ toNorm as)-  where go :: Norm -> JSValue-        go e =  case e of-                  UnitN _         -> showJSON "()"-                  BoolN b _       -> showJSON b-                  CharN c _       -> showJSON c-                  IntegerN i _    -> showJSON i-                  DoubleN d _     -> showJSON d-                  TextN t _       -> showJSON (Text.unpack t)-                  TupleN e1 e2 _  -> JSArray $ map go (e1 : deTuple e2)-                  ListN es _      -> JSArray $ map go es--deTuple :: Norm -> [Norm]-deTuple (TupleN e1 e2 _) = e1 : deTuple e2-deTuple n = [n]
src/Database/DSH/TH.hs view
@@ -1,585 +1,255 @@-{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}--module Database.DSH.TH-    (-      deriveTupleQA-    , generateDeriveTupleQARange-    , deriveTupleTA-    , generateDeriveTupleTARange-    , deriveTupleView-    , generateDeriveTupleViewRange--    , deriveQAForRecord-    , deriveQAForRecord'-    , deriveViewForRecord-    , deriveViewForRecord'-    , deriveTAForRecord-    , deriveTAForRecord'--    , generateDatabaseRecordInstances-    , generateTableRecordInstances-    , generateRecordInstances-    , generateTableDeclarations-    ) where---import Database.DSH.Data-import Database.DSH.Impossible--import Control.Applicative-import Control.Monad-import Data.Convertible-import Data.Char-import Data.List-import Database.HDBC-import Data.Text (Text)--- import Data.Time (UTCTime)-import GHC.Exts--import Language.Haskell.TH hiding (Q, TupleT, tupleT, AppE, VarE, reify, Type, ListT)-import qualified Language.Haskell.TH as TH-import Language.Haskell.TH.Syntax (sequenceQ)----- Create a "a -> b -> ..." type-arrowChainT :: [TypeQ] -> TypeQ-arrowChainT [] = $impossible-arrowChainT as = foldr1 (\a b -> arrowT `appT` a `appT` b) as---- Apply a list of 'TypeQ's to a type constructor-applyChainT :: TypeQ -> [TypeQ] -> TypeQ-applyChainT t ts = foldl' appT t ts---- Apply a list of 'Exp's to a some 'Exp'-applyChainE :: ExpQ -> [ExpQ] -> ExpQ-applyChainE e es = foldl' appE e es--applyChainTupleP :: [PatQ] -> PatQ-applyChainTupleP = foldr1 (\p1 p2 -> conP 'TupleN [p1,p2,wildP])--applyChainTupleE :: Name -> [ExpQ] -> ExpQ-applyChainTupleE n = foldr1 (\e1 e2 -> appE (appE (conE n) e1) e2)-------------------------------------------------------------------------------------- * QA instances------- Original Code--- instance (QA a,QA b) => QA (a,b) where---   reify _ = TupleT (reify (undefined :: a)) (reify (undefined :: b))---   toNorm (a,b) = TupleN (toNorm a) (toNorm b) (reify (a,b))---   fromNorm (TupleN a b (TupleT _ _)) = (fromNorm a,fromNorm b)---   fromNorm _ = $impossible--deriveTupleQA :: Int -> TH.Q [Dec]-deriveTupleQA l-    | l < 2     = $impossible-    | otherwise = pure `fmap` instanceD qaCxts-                                        qaType-                                        qaDecs--  where-    names@(a:b:rest) = [ mkName $ "a" ++ show i | i <- [1..l] ]--    qaCxts = return [ ClassP ''QA [VarT n] | n <- names ]-    qaType = conT ''QA `appT` applyChainT (TH.tupleT l) (map varT names)-    qaDecs = [ reifyDec-             , fromNormDec-             , toNormDec-             ]--    -- The class functions:--    reifyDec    = funD 'reify [reifyClause]-    reifyClause = clause [ wildP ]-                         ( normalB $ applyChainTupleE 'TupleT [ [| reify (undefined :: $_n) |] | _n <- map varT names ] )-                         []--    fromNormDec    = funD 'fromNorm [fromNormClause, clause [TH.wildP] (normalB [| $impossible |]) [] ]-    fromNormClause = clause [applyChainTupleP (map varP names)]-                            (normalB $ TH.tupE [ [| fromNorm $(varE n) |] | n <- names ])-                            []--    toNormDec    = funD 'toNorm [toNormClause]-    toNormClause = clause [ toNormClausePattern ] (normalB $ fst $ toNormClauseBody $ [ varE n | n <- names ]) []--    toNormClausePattern = tupP [ varP n | n <- names ]--    toNormClauseBody [a1,b1] =-      let t1 = [| TupleT (reify $a1) (reify $b1) |]-          e1 = [| TupleN (toNorm $a1) (toNorm $b1) ($t1) |]-      in  (e1,t1)-    toNormClauseBody (a1 : as1) =-      let (e1,t1) = toNormClauseBody as1-          t2 = [| TupleT (reify $a1) ($t1) |]-          e2 = [| TupleN (toNorm $a1) ($e1) ($t2) |]-      in  (e2,t2)-    toNormClauseBody _ = $impossible----- | Generate all 'QA' instances for tuples within range.-generateDeriveTupleQARange :: Int -> Int -> TH.Q [Dec]-generateDeriveTupleQARange from to =-    concat `fmap` sequenceQ [ deriveTupleQA n | n <- reverse [from..to] ]-------------------------------------------------------------------------------------- * TA instances------- Original code:--- instance (BasicType a, BasicType b, QA a, QA b) => TA (a,b) where--deriveTupleTA :: Int -> TH.Q [Dec]-deriveTupleTA l-    | l < 2     = $impossible-    | otherwise = pure `fmap` instanceD taCxts-                                        taType-                                        taDecs--  where-    names = [ mkName $ "a" ++ show i | i <- [1..l] ]--    taCxts = return $ concat [ [ClassP ''QA [VarT n], ClassP ''BasicType [VarT n]] | n <- names ]-    taType = conT ''TA `appT` applyChainT (TH.tupleT l) (map varT names)-    taDecs = []---- | Generate all 'TA' instances for tuples within range.-generateDeriveTupleTARange :: Int -> Int -> TH.Q [Dec]-generateDeriveTupleTARange from to =-    concat `fmap` sequenceQ [ deriveTupleTA n | n <- reverse [from..to] ]-------------------------------------------------------------------------------------- * View pattern------- Original code:--- instance (QA a,QA b) => View (Q (a,b)) (Q a, Q b) where---   view (Q a) = (Q (AppE (VarE "proj_2_1") a), Q (AppE (VarE "proj_2_1") a))--deriveTupleView :: Int -> TH.Q [Dec]-deriveTupleView l-    | l < 2     = $impossible-    | otherwise = pure `fmap` instanceD viewCxts-                                        viewType-                                        viewDecs--  where-    names = [ mkName $ "a" ++ show i | i <- [1..l] ]-    a = mkName "a"--    first  p = [| AppE1 Fst $p (typeTupleFst (typeExp $p)) |]-    second p = [| AppE1 Snd $p (typeTupleSnd (typeExp $p)) |]--    viewCxts = return [ ClassP ''QA [VarT n] | n <- names ]-    viewType = conT ''View `appT` (conT ''Q `appT` applyChainT (TH.tupleT l) (map varT names))-                           `appT` applyChainT (TH.tupleT l) [ conT ''Q `appT` varT n | n <- names ]--    viewDecs = [ viewDec, fromViewDec ]--    viewDec    = funD 'view [viewClause]-    viewClause = clause [ conP 'Q [varP a] ]-                        ( normalB $ TH.tupE [ if pos == l then [| Q $(f (varE a)) |] else [| Q $(first (f (varE a))) |]-                                            | pos <- [1..l]-                                            , let f = foldr (.) id (replicate (pos - 1) second)-                                            ])-                        []--    fromViewDec = funD 'fromView [fromViewClause]-    fromViewClause = clause [ fromViewClausePattern ]-                            ( normalB [| Q  $(fst $ fromViewClauseBody (map varE names)) |] )-                            []--    fromViewClausePattern = tupP (map (\n -> conP 'Q [varP n]) names)--    fromViewClauseBody [a1,b1] =-      let t1 = [| TupleT (typeExp $a1) (typeExp $b1) |]-          e1 = [| TupleE ($a1) ($b1) ($t1) |]-      in  (e1,t1)-    fromViewClauseBody (a1 : as1) =-      let (e1,t1) = fromViewClauseBody as1-          t2 = [| TupleT (typeExp $a1) ($t1) |]-          e2 = [| TupleE ($a1) ($e1) ($t2) |]-      in  (e2,t2)-    fromViewClauseBody _ = $impossible----- | Generate all 'View' instances for tuples within range.-generateDeriveTupleViewRange :: Int -> Int -> TH.Q [Dec]-generateDeriveTupleViewRange from to =-    concat `fmap` sequenceQ [ deriveTupleView n | n <- reverse [from..to] ]-------------------------------------------------------------------------------------- * Deriving Instances for Records------- | Derive the 'QA' instance for a record definition.-deriveQAForRecord :: TH.Q [Dec] -> TH.Q [Dec]-deriveQAForRecord q = do -  records <- q-  instances <- deriveQAForRecord' q-  return (records ++ instances)---- | Add 'QA' instance to a record without adding the actual data definition.--- Usefull in combination with 'deriveQAForRecord''-deriveQAForRecord' :: TH.Q [Dec] -> TH.Q [Dec]-deriveQAForRecord' q = do-    d <- q-    mapM addInst d-  where-    addInst d@(DataD [] dName [] [RecC rName rVar@(_:_)] _) | dName == rName = do--         let rCxt  = return []-             rType = conT ''QA `appT` conT dName-             rDec  = [ reifyDec-                     , toNormDec-                     , fromNormDec-                     ]--             reifyDec    = funD 'reify [reifyClause]-             reifyClause = clause [ wildP ]-                                  ( normalB $ applyChainTupleE 'TupleT [ [| reify (undefined :: $(return _t)) |] | (_,_,_t) <- rVar] )-                                  []--             names = [ mkName $ "a" ++ show i | i <- [1..length rVar] ]--             fromNormDec    = funD 'fromNorm [fromNormClause, failClause]-             fromNormClause = clause [ applyChainTupleP (map varP names) ]-                                     ( normalB $ (conE dName) `applyChainE` [ [| fromNorm $(varE n) |]-                                                                            | n <- names-                                                                            ]-                                     )-                                     []--             -- Fail with a verbose message where this happened-             failClause = clause [ wildP ]-                                 ( do loc <- location-                                      let pos = show (TH.loc_filename loc, fst (TH.loc_start loc), snd (TH.loc_start loc))-                                      normalB [| error $ "ferry: Impossible `fromNorm' at location " ++ pos |]-                                 )-                                 []--             toNormDec    = funD 'toNorm [toNormClause]-             toNormClause = clause [ conP dName (map varP names) ]-                                   ( normalB $ fst $ toNormClauseBody $ [ varE n | n <- names ] )-                                   []-                                   -             toNormClauseBody [a1,b1] =-                let t1 = [| TupleT (reify $a1) (reify $b1) |]-                    e1 = [| TupleN (toNorm $a1) (toNorm $b1) ($t1) |]-                in  (e1,t1)-             toNormClauseBody (a1 : as1) =-                let (e1,t1) = toNormClauseBody as1-                    t2 = [| TupleT (reify $a1) ($t1) |]-                    e2 = [| TupleN (toNorm $a1) ($e1) ($t2) |]-                in  (e2,t2)-             toNormClauseBody _ = $impossible---         instanceD rCxt-                   rType-                   rDec--    addInst _ = error "ferry: Failed to derive 'QA' - Invalid record definition"+module Database.DSH.TH (deriveQA, deriveTupleRangeQA, deriveElim) where --- | Derive the 'View' instance for a record definition. See--- 'deriveQAForRecord' for an example.-deriveViewForRecord :: TH.Q [Dec] -> TH.Q [Dec]-deriveViewForRecord q = do-  recrods <- q-  instances <- deriveViewForRecord' q-  return (recrods ++ instances)+import qualified Database.DSH.Internals  as DSH+import qualified Database.DSH.Impossible as DSH --- | Add 'View' instance to a record without adding the actual data definition.--- Usefull in combination with 'deriveQAForRecord''-deriveViewForRecord' :: TH.Q [Dec] -> TH.Q [Dec]-deriveViewForRecord' q = do-    d <- q-    concat `fmap` mapM addView d-  where-    addView (DataD [] dName [] [RecC rName rVar@(_:_)] dNames) | dName == rName = do+import Language.Haskell.TH -        -- The "View" record definition+-----------------+-- Deriving QA --+----------------- -        let vName  = mkName $ nameBase dName ++ "V"-            vRec   = recC vName [ return (prefixV n, s, makeQ t) | (n,s,t) <- rVar ]+deriveQA :: Name -> Q [Dec]+deriveQA name = do+  info <- reify name+  case info of+    TyConI (DataD    _cxt name1 tyVarBndrs cons _names) -> deriveTyConQA name1 tyVarBndrs cons+    TyConI (NewtypeD _cxt name1 tyVarBndrs con  _names) -> deriveTyConQA name1 tyVarBndrs [con]+    _                                                   -> fail errMsgExoticType -            prefixV :: Name -> Name-            prefixV n = mkName $ nameBase n ++ "V"+deriveTyConQA :: Name -> [TyVarBndr] -> [Con] -> Q [Dec]+deriveTyConQA name tyVarBndrs cons = do+  let context       = map (\tv -> ClassP ''DSH.QA [VarT (tyVarBndrToName tv)]) tyVarBndrs+  let typ           = foldl AppT (ConT name) (map (VarT . tyVarBndrToName) tyVarBndrs)+  let instanceHead  = AppT (ConT ''DSH.QA) typ+  let repDec        = deriveRep typ cons+  toExpDec <- deriveToExp cons+  frExpDec <- deriveFrExp cons+  return [InstanceD context instanceHead [repDec,toExpDec,frExpDec]] -            makeQ :: TH.Type -> TH.Type-            makeQ t = ConT ''Q `AppT` t+deriveTupleRangeQA :: Int -> Int -> Q [Dec]+deriveTupleRangeQA x y = fmap concat (mapM (deriveQA . tupleTypeName) [x .. y]) -            vNames = [] --dNames+-- Derive the Rep type function -        v <- dataD (return [])-                   vName-                   []-                   [vRec]-                   vNames+deriveRep :: Type -> [Con] -> Dec+deriveRep typ cons = TySynInstD ''DSH.Rep [typ] (deriveRepCons cons) -        -- The instance definition+deriveRepCons :: [Con] -> Type+deriveRepCons []  = error errMsgExoticType+deriveRepCons [c] = deriveRepCon c+deriveRepCons cs  = foldr1 (AppT . AppT (ConT ''(,)))+                           (map (AppT (ConT ''[]) . deriveRepCon) cs) -        let rCxt  = return []-            rType = conT ''View `appT` (conT ''Q `appT` conT dName)-                                `appT` (conT vName)-            rDec  = [ viewDec-                    , fromViewDec-                    ]+deriveRepCon :: Con -> Type+deriveRepCon con = case conToTypes con of+  [] -> ConT ''()+  ts -> foldr1 (AppT . AppT (ConT ''(,)))+               (map (AppT (ConT ''DSH.Rep)) ts) -            a = mkName "a"+-- Derive the toExp function of the QA class -            first  p = [| AppE1 Fst $p (typeTupleFst (typeExp $p)) |]-            second p = [| AppE1 Snd $p (typeTupleSnd (typeExp $p)) |]+deriveToExp :: [Con] -> Q Dec+deriveToExp [] = fail errMsgExoticType+deriveToExp cons = do+  clauses <- sequence (zipWith3 deriveToExpClause (repeat (length cons)) [0 .. ] cons)+  return (FunD 'DSH.toExp clauses) -            viewDec    = funD 'view [viewClause]-            viewClause = clause [ conP 'Q [varP a] ]-                                ( normalB $ applyChainE (conE vName)-                                          $ map (appE (conE 'Q))-                                          $ [ if pos == length rVar then (f (varE a)) else (first (f (varE a)))-                                            | pos <- [1 .. length rVar]-                                            , let f = foldr (.) id (replicate (pos - 1) second)-                                            ] )-                                []+deriveToExpClause :: Int -- Total number of constructors+                  -> Int -- Index of the constructor+                  -> Con+                  -> Q Clause+deriveToExpClause 0 _ _ = fail errMsgExoticType+deriveToExpClause 1 _ con = do+  (pat1,names1) <- conToPattern con+  let exp1 = deriveToExpMainExp names1+  let body1 = NormalB exp1+  return (Clause [pat1] body1 [])+deriveToExpClause n i con = do+  (pat1,names1) <- conToPattern con+  let exp1 = deriveToExpMainExp names1+  expList1 <- [| DSH.ListE [ $(return exp1) ] |]+  expEmptyList <- [| DSH.ListE [] |]+  let lists = replicate i expEmptyList ++ [expList1] ++ replicate (n - i - 1) expEmptyList+  let exp2 = foldr1 (AppE . AppE (ConE 'DSH.PairE)) lists+  let body1 = NormalB exp2+  return (Clause [pat1] body1 []) -            -- names for variables used in the `fromView' function-            qs = [ mkName $ "q" ++ show i | i <- [1.. length rVar] ]+deriveToExpMainExp :: [Name] -> Exp+deriveToExpMainExp []     = ConE 'DSH.UnitE+deriveToExpMainExp [name] = AppE (VarE 'DSH.toExp) (VarE name)+deriveToExpMainExp names  = foldr1 (AppE . AppE (ConE 'DSH.PairE))+                                   (map (AppE (VarE 'DSH.toExp) . VarE) names)+-- Derive to frExp function of the QA class -            fromViewDec    = funD 'fromView [fromViewClause] --, failClause]-            fromViewClause = clause [ conP vName [ conP 'Q [varP q1] | q1 <- qs ] ]-                                    ( normalB [| Q  $(fst $ fromViewClauseBody (map varE qs)) |] )-                                    []+deriveFrExp :: [Con] -> Q Dec+deriveFrExp cons = do+  clauses <- sequence (zipWith3 deriveFrExpClause (repeat (length cons)) [0 .. ] cons)+  imp <- DSH.impossible+  let lastClause = Clause [WildP] (NormalB imp) []+  return (FunD 'DSH.frExp (clauses ++ [lastClause])) -            fromViewClauseBody [a1,b1] =-              let t1 = [| TupleT (typeExp $a1) (typeExp $b1) |]-                  e1 = [| TupleE ($a1) ($b1) ($t1) |]-              in  (e1,t1)-            fromViewClauseBody (a1 : as1) =-              let (e1,t1) = fromViewClauseBody as1-                  t2 = [| TupleT (typeExp $a1) ($t1) |]-                  e2 = [| TupleE ($a1) ($e1) ($t2) |]-              in  (e2,t2)-            fromViewClauseBody _ = $impossible+deriveFrExpClause :: Int -- Total number of constructors+                  -> Int -- Index of the constructor+                  -> Con+                  -> Q Clause+deriveFrExpClause 1 _ con = do+  (_,names1) <- conToPattern con+  let pat1 = deriveFrExpMainPat names1+  let exp1 = foldl AppE (ConE (conToName con)) (map (AppE (VarE 'DSH.frExp) . VarE) names1)+  let body1 = NormalB exp1+  return (Clause [pat1] body1 [])+deriveFrExpClause n i con = do+  (_,names1) <- conToPattern con+  let pat1 = deriveFrExpMainPat names1+  let patList1 = ConP 'DSH.ListE [ConP '(:) [pat1,WildP]]+  let lists = replicate i WildP ++ [patList1] ++ replicate (n - i - 1) WildP+  let pat2 = foldr1 (\p1 p2 -> ConP 'DSH.PairE [p1,p2]) lists+  let exp1 = foldl AppE (ConE (conToName con)) (map (AppE (VarE 'DSH.frExp) . VarE) names1)+  let body1 = NormalB exp1+  return (Clause [pat2] body1 []) +deriveFrExpMainPat :: [Name] -> Pat+deriveFrExpMainPat [] = ConP 'DSH.UnitE []+deriveFrExpMainPat [name] = VarP name+deriveFrExpMainPat names  = foldr1 (\p1 p2 -> ConP 'DSH.PairE [p1,p2]) (map VarP names) +-------------------+-- Deriving Elim --+------------------- -            -- Fail with a verbose message where this happened-            failClause = clause [ wildP ]-                                ( do loc <- location-                                     let pos = show (TH.loc_filename loc, fst (TH.loc_start loc), snd (TH.loc_start loc))-                                     normalB [| error $ "ferry: Impossible `fromView' at location " ++ pos |]-                                )-                                []+deriveElim :: Name -> Q [Dec]+deriveElim name = do+  info <- reify name+  case info of+    TyConI (DataD    _cxt name1 tyVarBndrs cons _names) -> deriveTyConElim name1 tyVarBndrs cons+    TyConI (NewtypeD _cxt name1 tyVarBndrs con  _names) -> deriveTyConElim name1 tyVarBndrs [con]+    _ -> fail errMsgExoticType -        i <- instanceD rCxt-                       rType-                       rDec+deriveTyConElim :: Name -> [TyVarBndr] -> [Con] -> Q [Dec]+deriveTyConElim name tyVarBndrs cons = do+  resultTyName <- newName "r"+  let resTy = VarT resultTyName+  let ty = foldl AppT (ConT name) (map (VarT . tyVarBndrToName) tyVarBndrs)+  let context = (ClassP ''DSH.QA [ty])    :+                (ClassP ''DSH.QA [resTy]) :+                map (\tv -> ClassP ''DSH.QA [VarT (tyVarBndrToName tv)]) tyVarBndrs+  let instanceHead = AppT (AppT (ConT ''DSH.Elim) ty) resTy+  let eliminatorDec = deriveEliminator ty resTy cons+  elimDec <- deriveElimFun cons+  return [InstanceD context instanceHead [eliminatorDec,elimDec]] -        return [v,i]+-- Derive the Eliminator type function -    addView _ = error "ferry: Failed to derive 'View' - Invalid record definition"+deriveEliminator :: Type -> Type -> [Con] -> Dec+deriveEliminator typ resTy cons = TySynInstD ''DSH.Eliminator [typ,resTy] (deriveEliminatorCons resTy cons) +deriveEliminatorCons :: Type -> [Con] -> Type+deriveEliminatorCons _ []  = error errMsgExoticType+deriveEliminatorCons resTy cs  =+  foldr (AppT . AppT ArrowT)+        (AppT (ConT ''DSH.Q) resTy)+        (map (deriveEliminatorCon resTy) cs) --- | Derive 'TA' instances-deriveTAForRecord :: TH.Q [Dec] -> TH.Q [Dec]-deriveTAForRecord q = do-  records <- q-  instances <- deriveTAForRecord' q-  return (records ++ instances)+deriveEliminatorCon :: Type -> Con -> Type+deriveEliminatorCon resTy con =+  foldr (AppT . AppT ArrowT)+        (AppT (ConT ''DSH.Q) resTy)+        (map (AppT (ConT ''DSH.Q)) (conToTypes con)) -deriveTAForRecord' :: TH.Q [Dec] -> TH.Q [Dec]-deriveTAForRecord' q = q >>= mapM addTA-  where-    addTA (DataD [] dName [] [RecC rName (_:_)] _) | dName == rName =+-- Derive the elim function of the Elim type class -        let taCxt  = return []-            taType = conT ''TA `appT` conT dName-            taDec  = [ ]+deriveElimFun :: [Con] -> Q Dec+deriveElimFun cons = do+  clause1 <- deriveElimFunClause cons+  return (FunD 'DSH.elim [clause1]) -        in instanceD taCxt-                     taType-                     taDec+deriveElimFunClause :: [Con] -> Q Clause+deriveElimFunClause cons = do+  en  <- newName "e"+  fns <- mapM (\ _ -> newName "f") cons+  let fes = map VarE fns+  let pats1 = (ConP 'DSH.Q [VarP en]) : map VarP fns -    addTA _ = error "ferry: Failed to derive 'TA' - Invalid record definition"+  fes2 <- sequence (zipWith deriveElimToLamExp fes (map (length . conToTypes) cons)) +  let e       = VarE en+  let liste   = AppE (ConE 'DSH.ListE) (ListE (deriveElimFunClauseExp e fes2))+  let concate = AppE (AppE (ConE 'DSH.AppE) (ConE 'DSH.Concat)) liste+  let heade   = AppE (AppE (ConE 'DSH.AppE) (ConE 'DSH.Head)) concate+  let qe      = AppE (ConE 'DSH.Q) heade+  return (Clause pats1 (NormalB qe) []) --- | Create lifted record selectors-recordQSelectors :: TH.Q [Dec] -> TH.Q [Dec]-recordQSelectors q = do-  recrods <- q-  selectors <- recordQSelectors' q-  return (recrods ++ selectors)+deriveElimToLamExp :: Exp -> Int -> Q Exp+deriveElimToLamExp f 0 =+  return (AppE (VarE 'const) (AppE (VarE 'DSH.unQ) f))+deriveElimToLamExp f 1 = do+  xn <- newName "x"+  let xe = VarE xn+  let xp = VarP xn+  let qe = AppE (ConE 'DSH.Q) xe+  let fappe = AppE f qe+  let unqe = AppE (VarE 'DSH.unQ) fappe+  return (LamE [xp] unqe)+deriveElimToLamExp f n = do+  xn <- newName "x"+  let xe = VarE xn+  let xp = VarP xn+  let fste = AppE (AppE (ConE 'DSH.AppE) (ConE 'DSH.Fst)) xe+  let snde = AppE (AppE (ConE 'DSH.AppE) (ConE 'DSH.Snd)) xe+  let qe = AppE (ConE 'DSH.Q) fste+  let fappe = AppE f qe+  f' <- deriveElimToLamExp fappe (n - 1)+  return (LamE [xp] (AppE f' snde)) -recordQSelectors' :: TH.Q [Dec] -> TH.Q [Dec]-recordQSelectors' q = q >>= fmap join . mapM addSel+deriveElimFunClauseExp :: Exp -> [Exp] -> [Exp]+deriveElimFunClauseExp _ [] = error errMsgExoticType+deriveElimFunClauseExp e [f] = [AppE (ConE 'DSH.ListE) (ListE [AppE f e])]+deriveElimFunClauseExp e fs = go e fs   where-    addSel :: Dec -> TH.Q [Dec]-    addSel (DataD [] dName [] [RecC rName vst] _) | dName == rName && not (null vst) =--        let namesAndTypes = [ (n, t')-                            | (n, _, t) <- vst-                            , let t' = arrowChainT [ conT ''Q `appT` conT dName-                                                   , conT ''Q `appT` return t-                                                   ]-                            ]--            addFunD (n,t) = let qn = mkName $ nameBase n ++ "Q"-                                vn = mkName $ nameBase n ++ "V"-                             in sequenceQ [ sigD qn t-                                          , funD qn [ clause []-                                                             (normalB [| $(varE vn) . view |])-                                                             []-                                                    ]-                                          ]--         in if null namesAndTypes-               then error "woot?"-               else concat `fmap` mapM addFunD namesAndTypes--    addSel _ = error "ferry: Failed to create record selectors - Invalid record definition"-------------------------------------------------------------------------------------- * Exported enduser functions------- | Generate table declarations for all tables in the database. This function--- should be used in conjunction with generateDatabaseRecordInstances. For--- example, this function generates the following code for the table 'users':------ > users :: Q [User]--- > users = table "users"----generateTableDeclarations :: (IConnection conn)-                             => (IO conn)  -- ^ Database connection-                             -> TH.Q [Dec]-generateTableDeclarations conn = do-  tables <- runIO $ do  c <- conn-                        r <- getTables c-                        disconnect c-                        return r-  declss <- mapM generateTableDeclaration tables-  return (concat declss)--generateTableDeclaration :: String -> TH.Q [Dec]-generateTableDeclaration s = return-  [ TH.SigD (mkName s) (TH.AppT (TH.ConT ''Q) (TH.AppT TH.ListT (TH.ConT (mkName (dataTypeName s)))))-  , TH.FunD (mkName s) [TH.Clause [] (TH.NormalB (TH.AppE (TH.VarE (mkName "table")) (TH.LitE (TH.StringL s)))) []]-  ]---- | Create corresponding Haskell record data types and generate QA and View--- instances for all tables in the database (except for system tables).------ Example usage:------ > $(generateDatabaseRecordInstances myConnection)------ Note that the database information is queried at compile time, not at run time!-generateDatabaseRecordInstances :: (IConnection conn)-                             => (IO conn)  -- ^ Database connection-                             -> TH.Q [Dec]-generateDatabaseRecordInstances conn = do-  tables <- runIO $ do  c <- conn-                        r <- getTables c-                        disconnect c-                        return r-  decss <- mapM (\t -> generateTableRecordInstances conn t (dataTypeName t) [''Show,''Eq]) tables-  return (concat decss)--dataTypeName :: String -> String-dataTypeName []       = []-dataTypeName [c]      = map toUpper (cleanUnderscores [c])-dataTypeName (c : cs) = toUpper c : cleanUnderscores (init cs)--cleanUnderscores :: String -> String-cleanUnderscores []             = []-cleanUnderscores ['_']          = [] -cleanUnderscores ('_' : c : cs) = toUpper c : cleanUnderscores cs-cleanUnderscores (c : cs)       = c : cleanUnderscores cs---- | Lookup a database table, create corresponding Haskell record data types--- and generate QA and View instances------ Example usage:------ > $(generateTableRecordInstances myConnection "users" "User" [''Show,''Eq])------ Note that the table information is queried at compile time, not at run time!-generateTableRecordInstances  :: (IConnection conn)-                              => (IO conn)  -- ^ Database connection-                              -> String     -- ^ Table name-                              -> String     -- ^ Data type name for each row of the table-                              -> [Name]     -- ^ Default deriving instances-                              -> TH.Q [Dec]-generateTableRecordInstances conn t dname dnames = do-    tdesc <- runIO $ do c <- conn-                        r <- describeTable c t-                        disconnect c-                        return r-    generateRecordInstances (createDataType (sortWith fst tdesc))+  go :: Exp -> [Exp] -> [Exp]+  go _ []  = error errMsgExoticType+  go e1 [f1] =+    let paire = AppE (AppE (ConE 'DSH.PairE) (AppE (ConE 'DSH.LamE) f1)) e1+    in  [AppE (AppE (ConE 'DSH.AppE) (ConE 'DSH.Map)) paire]+  go e1 (f1 : fs1) =+    let fste  = AppE (AppE (ConE 'DSH.AppE) (ConE 'DSH.Fst)) e1+        snde  = AppE (AppE (ConE 'DSH.AppE) (ConE 'DSH.Snd)) e1+        paire = AppE (AppE (ConE 'DSH.PairE) (AppE (ConE 'DSH.LamE) f1)) fste+        mape  = AppE (AppE (ConE 'DSH.AppE) (ConE 'DSH.Map)) paire+    in  mape : go snde fs1 -  where-    createDataType :: [(String, SqlColDesc)] -> TH.Q [Dec]-    createDataType [] = error "ferry: Empty table description"-    createDataType ds = pure `fmap` dataD dCxt-                                          dName-                                          []-                                          [dCon ds]-                                          dNames+-- Helper Functions -    dName     = mkName dname-    dNames    = dnames+conToTypes :: Con -> [Type]+conToTypes (NormalC _name strictTypes) = map snd strictTypes+conToTypes (RecC _name varStrictTypes) = map (\(_,_,t) -> t) varStrictTypes+conToTypes (InfixC st1 _name st2) = [snd st1,snd st2]+conToTypes (ForallC _tyVarBndrs _cxt con) = conToTypes con -    dCxt      = return []-    dCon desc = recC dName (map toVarStrictType desc)+tyVarBndrToName :: TyVarBndr -> Name+tyVarBndrToName (PlainTV name) = name+tyVarBndrToName (KindedTV name _kind) = name -    -- no support for nullable columns yet:-    toVarStrictType (n,SqlColDesc { colType = ty, colNullable = _ }) =-        let t' = case convert ty of-                      IntegerT    -> ConT ''Integer-                      BoolT       -> ConT ''Bool-                      CharT       -> ConT ''Char-                      DoubleT     -> ConT ''Double-                      TextT       -> ConT ''Text-                      _           -> $impossible+conToPattern :: Con -> Q (Pat,[Name])+conToPattern (NormalC name strictTypes) = do+  ns <- mapM (\ _ -> newName "x") strictTypes+  return (ConP name (map VarP ns),ns)+conToPattern (RecC name varStrictTypes) = do+  ns <- mapM (\ _ -> newName "x") varStrictTypes+  return (ConP name (map VarP ns),ns)+conToPattern (InfixC st1 name st2) = do+  ns <- mapM (\ _ -> newName "x") [st1,st2]+  return (ConP name (map VarP ns),ns)+conToPattern (ForallC _tyVarBndr _cxt con) = conToPattern con -        in return (mkName n, NotStrict, t')+conToName :: Con -> Name+conToName (NormalC name _) = name+conToName (RecC name _) = name+conToName (InfixC _ name _) = name+conToName (ForallC _ _ con)	= conToName con +-- Error messages --- | Derive QA and View instances for record definitions------ Example usage:------ > $(generateRecordInstances [d|--- >--- >     data User = User--- >         { userId    :: Int--- >         , userName  :: String--- >         }--- >--- >   |])------ This generates the following record type, which can be used in view patterns------ > data UserV = UserV--- >     { userIdV    :: Q Int--- >     , userNameV  :: Q String--- >     }------ > instance View (Q User) UserV------ and the liftet record selectors:------ > userIdQ      :: Q User -> Q Int--- > userNameQ    :: Q User -> Q String-generateRecordInstances :: TH.Q [Dec] -> TH.Q [Dec]-generateRecordInstances q = do-    d  <- q-    qa <- deriveQAForRecord' q-    v  <- deriveViewForRecord' q-    ta <- deriveTAForRecord' q-    rs <- recordQSelectors' q-    return (d ++ qa ++ v ++ ta ++ rs)+errMsgExoticType :: String+errMsgExoticType =  "Automatic derivation of DSH related type class instances only works for Haskell 98 types."
− src/Database/DSH/XHTML.hs
@@ -1,47 +0,0 @@-module Database.DSH.XHTML (xhtmlExport, xhtmlExportHandle, xhtmlExportStdout) where--import Database.DSH.Data hiding (table)--import Text.XHtml.Strict--import qualified Data.Text as Text--import qualified System.IO as IO-import System.IO (Handle)--xhtmlExport :: (QA a) => FilePath -> [a] -> IO ()-xhtmlExport file as = IO.withFile file IO.WriteMode (\handle -> xhtmlExportHandle handle as)--xhtmlExportStdout :: (QA a) => [a] -> IO ()-xhtmlExportStdout = xhtmlExportHandle IO.stdout--xhtmlExportHandle :: (QA a) => Handle -> [a] -> IO ()-xhtmlExportHandle handle as = IO.hPutStr handle (showHtmlFragment $ go 0 0 $ toNorm as)-  where go :: Integer -> Integer -> Norm -> Html-        go tl rl e =  case e of-                        UnitN _         -> (td $ stringToHtml $ "()")           ! [tdAttr tl rl]-                        BoolN b _       -> (td $ stringToHtml $ show b)         ! [tdAttr tl rl]-                        CharN c _       -> (td $ stringToHtml $ [c])            ! [tdAttr tl rl]-                        IntegerN i _    -> (td $ stringToHtml $ show i)         ! [tdAttr tl rl]-                        DoubleN d _     -> (td $ stringToHtml $ show d)         ! [tdAttr tl rl]-                        TextN t _       -> (td $ stringToHtml $ Text.unpack t)  ! [tdAttr tl rl]-                        TupleN e1 e2 _  -> (concatHtml $ map (go tl rl) (e1 : deTuple e2))-                        ListN es _      -> td $ (table  $ concatHtml-                                                        $ map (\(l1,e1) -> tr (go (tl + 1) l1 e1))-                                                        $ zip [0 ..] es-                                                ) ! [tableAttr]--        tdAttr :: Integer -> Integer -> HtmlAttr-        tdAttr tl rl = case (odd tl,odd rl) of-                         (False,False) -> strAttr "style" "text-align:center; min-width:20px; padding:5px; background-color:#EEE;"-                         (False,True)  -> strAttr "style" "text-align:center; min-width:20px; padding:5px; background-color:#CCC;"-                         (True,False)  -> strAttr "style" "text-align:center; min-width:20px; padding:5px; background-color:#DDD;"-                         (True,True)   -> strAttr "style" "text-align:center; min-width:20px; padding:5px; background-color:#E9E9E9;"--        tableAttr :: HtmlAttr-        tableAttr = strAttr "style" "border-spacing:5px;"---deTuple :: Norm -> [Norm]-deTuple (TupleN e1 e2 _) = e1 : deTuple e2-deTuple n = [n]
tests/Main.hs view
@@ -1,5 +1,3 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}- module Main where  import qualified Database.DSH as Q@@ -62,7 +60,7 @@     qc prop_maybe_integer     putStrPad "Either Integer Integer: "     qc prop_either_integer-    +     putStrLn ""     putStrLn "Equality, Boolean Logic and Ordering"     putStrLn "------------------------------------"@@ -102,7 +100,7 @@     qc prop_fst     putStrPad "snd"     qc prop_snd-    +     putStrLn ""     putStrLn "Numerics:"     putStrLn "-----------"@@ -130,7 +128,7 @@     qc prop_negate_integer     putStrPad "negate_double"     qc prop_negate_double-    +     putStrLn ""     putStrLn "Maybe"     putStrLn "-----"@@ -174,7 +172,7 @@     qc prop_rights     putStrPad "partitionEithers"     qc prop_partitionEithers-    +     putStrLn ""     putStrLn "Lists"     putStrLn "-----"@@ -271,8 +269,8 @@     let hs = f2 arg     assert (db == hs) -makePropNotNull ::  (Eq b, Q.QA a, Q.QA b, Show a, Show b)-                    => (Q.Q [a] -> Q.Q b)+makePropNotNull ::  (Eq b, QA a, QA b, Show a, Show b)+                    => (Q [a] -> Q b)                     -> ([a] -> b)                     -> [a]                     -> Property@@ -284,14 +282,14 @@                   -> a                   -> Property makePropDouble f1 f2 arg = monadicIO $ do-    c  <- run $ getConn+    c  <- run getConn     db <- run $ fromQ c $ f1 (Q.toQ arg)     run $ HDBC.disconnect c     let hs = f2 arg     let eps = 1.0E-8 :: Double;         assert (abs (db - hs) < eps) -uncurryQ :: (Q.QA a, Q.QA b) => (Q.Q a -> Q.Q b -> Q.Q c) -> Q.Q (a,b) -> Q.Q c+uncurryQ :: (QA a, QA b) => (Q a -> Q b -> Q c) -> Q (a,b) -> Q c uncurryQ f = uncurry f . Q.view  -- * Supported Types@@ -347,7 +345,7 @@ prop_neq = makeProp (uncurryQ (Q./=)) (uncurry (/=))  prop_cond :: Bool -> Property-prop_cond = makeProp (\b -> Q.cond b (0 :: Q Integer) 1) (\b -> if b then 0 else 1)+prop_cond = makeProp (\b -> Q.cond b 0 1) (\b -> if b then (0 :: Integer) else 1)  prop_lt :: (Integer, Integer) -> Property prop_lt = makeProp (uncurryQ (Q.<)) (uncurry (<))@@ -419,7 +417,7 @@ prop_isRight :: Either Integer Integer -> Property prop_isRight = makeProp Q.isRight (\e -> case e of {Left _ -> False; Right _ -> True;}) -prop_either :: (Either Integer Integer) -> Property+prop_either :: Either Integer Integer -> Property prop_either =  makeProp (Q.either id id) (either id id)  prop_lefts :: [Either Integer Integer] -> Property@@ -440,7 +438,7 @@ prop_snoc = makeProp (uncurryQ (Q.|>)) (\(a,b) -> a ++ [b])  prop_singleton :: Integer -> Property-prop_singleton = makeProp Q.singleton (\x -> [x])+prop_singleton = makeProp Q.singleton (: [])  prop_head  :: [Integer] -> Property prop_head  = makePropNotNull Q.head head@@ -479,7 +477,7 @@ prop_map = makeProp (Q.map id) (map id)  prop_append :: ([Integer], [Integer]) -> Property-prop_append = makeProp (uncurryQ (Q.><)) (\(a,b) -> a ++ b)+prop_append = makeProp (uncurryQ (Q.++)) (uncurry (++))  prop_filter :: [Integer] -> Property prop_filter = makeProp (Q.filter (const $ Q.toQ True)) (filter $ const True)@@ -494,7 +492,7 @@ prop_null = makeProp Q.null null  prop_length :: [Integer] -> Property-prop_length = makeProp Q.length (fromIntegral . length)+prop_length = makeProp Q.length ((fromIntegral :: Int -> Integer) . length)  prop_reverse :: [Integer] -> Property prop_reverse = makeProp Q.reverse reverse@@ -521,7 +519,7 @@ prop_concat = makeProp Q.concat concat  prop_concatMap :: [Integer] -> Property-prop_concatMap = makeProp (Q.concatMap Q.singleton) (concatMap (\a -> [a]))+prop_concatMap = makeProp (Q.concatMap Q.singleton) (concatMap (: []))  prop_maximum :: [Integer] -> Property prop_maximum = makePropNotNull Q.maximum maximum@@ -549,16 +547,16 @@                      (uncurry   $   break . (==) . fromIntegral)  prop_elem :: (Integer, [Integer]) -> Property-prop_elem = makeProp (uncurryQ $ Q.elem)-                     (uncurry  $   elem)+prop_elem = makeProp (uncurryQ Q.elem)+                     (uncurry    elem)  prop_notElem :: (Integer, [Integer]) -> Property-prop_notElem = makeProp (uncurryQ $ Q.notElem)-                        (uncurry  $   notElem)+prop_notElem = makeProp (uncurryQ Q.notElem)+                        (uncurry    notElem)  prop_lookup :: (Integer, [(Integer,Integer)]) -> Property-prop_lookup = makeProp (uncurryQ $ Q.lookup)-                       (uncurry  $   lookup)+prop_lookup = makeProp (uncurryQ Q.lookup)+                       (uncurry    lookup)  prop_zip :: ([Integer], [Integer]) -> Property prop_zip = makeProp (uncurryQ Q.zip) (uncurry zip)
tests/Makefile view
@@ -1,5 +1,5 @@ all: cabal-		ghc -Wall -O3 --make Main.hs -o Main+		ghc -Wall -O3 -fno-warn-orphans --make Main.hs -o Main 		./Main  hpc: cabal@@ -10,7 +10,7 @@ 		hpc markup Main  cabal: clean-		cd ..; cabal clean; cabal install; cd tests;+		cd ..; cabal install; cd tests;  clean: 		rm -rf tmp .hpc *.html *.tix *.o *.hi Main