packages feed

Rlang-QQ 0.2.1.0 → 0.3.0.0

raw patch · 10 files changed

+214/−214 lines, 10 filesdep +Rlang-QQdep +SHAdep +data-binary-ieee754dep ~HListdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: Rlang-QQ, SHA, data-binary-ieee754, hspec, lens

Dependency ranges changed: HList, base

API changes (from Hackage documentation)

- HListExtras: FApply :: FApply
- HListExtras: data FApply
- HListExtras: instance (ApplyAB f a b, ab ~ (a -> b)) => ApplyAB FApply f ab
- RlangQQ.Binary: instance (FromRDSRec a b as' as'2 bs') => FromRDS (Record bs')
- RlangQQ.Binary: instance (RDSHLIST2 ___ __ l) => FromRDS (LST l)
- RlangQQ.Binary: instance (ShowLabel x, RecordLabelsString xs) => RecordLabelsString (x : xs)
- RlangQQ.Binary: instance (Tagged l a ~ x, y ~ Label l) => ApplyAB FLabelLVPair x y
- RlangQQ.Binary: instance (string ~ String, ShowLabel l, ll ~ Label l) => ApplyAB FShowLabel ll string
- RlangQQ.Binary: instance Tagged l a ~ b => ApplyAB FLVPair a b
- RlangQQ.FN: FN :: FN
- RlangQQ.FN: NoLabel :: NoLabel
- RlangQQ.FN: data FN
- RlangQQ.FN: data NoLabel
- RlangQQ.FN: instance (a ~ Tagged t (Tagged t2 x), b ~ Tagged t x) => ApplyAB FN a b
- RlangQQ.FN: instance la ~ Tagged "" a => ApplyAB NoLabel a la
- RlangQQ.Internal: classifyByConT :: [(String, b)] -> Q ([(String, b)], [(String, b)], [(String, b)])
- RlangQQ.Internal: getConTOf :: String -> Q (Maybe Name)
- RlangQQ.MakeRecord: NoLabel :: NoLabel
- RlangQQ.MakeRecord: data NoLabel
- RlangQQ.MakeRecord: instance Tagged "" a ~ la => ApplyAB NoLabel a la
- RlangQQ.MakeRecord: type ListToRecN __ (n :: HNat) x r = (HReplicate n (StateT [x] Identity x), HSequence (StateT [x] Identity) (HReplicateR n (StateT [x] Identity x)) __, HMapCxt NoLabel (HList __) (HList r) __ r)
+ RlangQQ.Binary: instance (FromRDSRec b d) => FromRDS (Record d)
+ RlangQQ.Binary: instance (RDSHLIST2 __ l) => FromRDS (LST l)
+ RlangQQ.Binary: instance (ShowLabel x, RecordLabelsString xs) => RecordLabelsString (Label x : xs)
+ RlangQQ.Binary: instance RDA a1 ~ t0 => Rewrapped (RDA a0) t0
+ RlangQQ.Binary: instance Wrapped (RDA a0)
+ RlangQQ.Internal: addLambda :: Map Int (Set String) -> ExpQ -> ExpQ
- RlangQQ: listToRecN :: ListToRecN __ (n :: HNat) x r => Proxy n -> [x] -> Record r
+ RlangQQ: listToRecN :: (HAllTaggedLV (HReplicateR * n (Tagged Symbol "" x)), SameLabels [*] [*] (HReplicateR * n (Tagged Symbol "" x)) (HReplicateR * n (Tagged Symbol "" x)), SameLength' * * (RecordValuesR (HReplicateR * n (Tagged Symbol "" x))) (RecordValuesR (HReplicateR * n (Tagged Symbol "" x))), SameLength' * * (HReplicateR * n (Tagged Symbol "" x)) (HReplicateR * n (Tagged Symbol "" x)), HList2List (RecordValuesR (HReplicateR * n (Tagged Symbol "" x))) x, HMapAux HList TaggedFn (RecordValuesR (HReplicateR * n (Tagged Symbol "" x))) (HReplicateR * n (Tagged Symbol "" x)), RecordValues (HReplicateR * n (Tagged Symbol "" x))) => Proxy HNat n -> [x] -> Record (HReplicateR * n (Tagged Symbol "" x))
- RlangQQ.Binary: fromRDA :: FromRDA __ r => ByteString -> Record r
+ RlangQQ.Binary: fromRDA :: FromRDA r => ByteString -> Record r
- RlangQQ.Binary: type FromRDA a r = (HMapCxt FLVPair (HList a) (HList r) a r, FromRDS (RDA a))
+ RlangQQ.Binary: type FromRDA r = (Unlabeled' r, FromRDS (RDA (RecordValuesR r)))
- RlangQQ.Binary: type ToRDSRecord __ ___ xs = (RDSHLIST __ ___, ToRDS (LST ___), RecordValues xs, HList ___ ~ (HList (RecordValuesR xs) `HAppendR` HList '[ListStart, Tagged "names" [String]]), RecordLabelsString (RecordLabels xs), HAppend (HList (RecordValuesR xs)) (HList '[ListStart, Tagged "names" [String]]))
+ RlangQQ.Binary: type ToRDSRecord __ ___ xs = (RDSHLIST __ ___, ToRDS (LST ___), RecordValues xs, HList ___ ~ (HList (RecordValuesR xs) `HAppendR` HList '[ListStart, Tagged "names" [String]]), RecordLabelsString (LabelsOf xs), HAppend (HList (RecordValuesR xs)) (HList '[ListStart, Tagged "names" [String]]))
- RlangQQ.MakeRecord: listToRecN :: ListToRecN __ (n :: HNat) x r => Proxy n -> [x] -> Record r
+ RlangQQ.MakeRecord: listToRecN :: (HAllTaggedLV (HReplicateR * n (Tagged Symbol "" x)), SameLabels [*] [*] (HReplicateR * n (Tagged Symbol "" x)) (HReplicateR * n (Tagged Symbol "" x)), SameLength' * * (RecordValuesR (HReplicateR * n (Tagged Symbol "" x))) (RecordValuesR (HReplicateR * n (Tagged Symbol "" x))), SameLength' * * (HReplicateR * n (Tagged Symbol "" x)) (HReplicateR * n (Tagged Symbol "" x)), HList2List (RecordValuesR (HReplicateR * n (Tagged Symbol "" x))) x, HMapAux HList TaggedFn (RecordValuesR (HReplicateR * n (Tagged Symbol "" x))) (HReplicateR * n (Tagged Symbol "" x)), RecordValues (HReplicateR * n (Tagged Symbol "" x))) => Proxy HNat n -> [x] -> Record (HReplicateR * n (Tagged Symbol "" x))

Files

+ Changelog.md view
@@ -0,0 +1,6 @@+# 0.3+Support positional arguments++Write input/output files to Rtmp/<hash>/ because+different hs files would create the same filename+for R input/output.
Rlang-QQ.cabal view
@@ -1,5 +1,5 @@ name: Rlang-QQ-version: 0.2.1.0+version: 0.3.0.0 cabal-version: >=1.10 build-type: Simple license: BSD3@@ -27,6 +27,7 @@                     examples/*.ipynb                     examples/*.html                     examples/Makefile+                    Changelog.md  source-repository head     type: darcs@@ -57,14 +58,31 @@     if (impl(ghc > 7.7))       default-extensions: AllowAmbiguousTypes -    build-depends: base ==4.*, containers,-                   template-haskell <= 3, directory, process,-                   trifecta >= 1.4, utf8-string ==0.3.*, bytestring,-                   Cabal, syb, mtl, transformers,-                   binary, vector, HList >= 0.3.4, temporary,-                   text, array, zlib,-                   filepath, split,-                   haskell-src-meta+    build-depends: base ==4.*,+                   array,+                   binary,+                   bytestring,+                   Cabal,+                   containers,+                   data-binary-ieee754,+                   directory,+                   filepath,+                   haskell-src-meta,+                   HList >= 0.4,+                   lens,+                   mtl,+                   process,+                   SHA,+                   split,+                   syb,+                   template-haskell <= 3,+                   temporary,+                   text,+                   transformers,+                   trifecta >= 1.4,+                   utf8-string ==0.3.*,+                   vector,+                   zlib      if flag(repa)       build-depends: repa@@ -73,12 +91,10 @@     exposed-modules: RlangQQ.Internal                      RlangQQ.Binary                      RlangQQ.Antiquote-                     RlangQQ.FN                      RlangQQ.NatQQ                      RlangQQ.MakeRecord                      RlangQQ.ParseKnitted                      RlangQQ-                     HListExtras      other-modules:  Paths_Rlang_QQ @@ -90,7 +106,20 @@   default: True   test-suite doctests+  default-language: Haskell2010   type:          exitcode-stdio-1.0   ghc-options:   -threaded   main-is:       doctests.hs   build-depends: base, doctest >= 0.8++test-suite hspec+  default-language: Haskell2010+  type:          exitcode-stdio-1.0+  main-is: examples/tests.hs+  build-depends: base,+                 hspec,+                 lens,+                 directory,+                 vector,+                 Rlang-QQ+  -- build-tools: HListPP
doctests.hs view
@@ -1,7 +1,17 @@ import Test.DocTest main = doctest $ "-isrc": "-idist/build/autogen":-    "examples/test2.hs":-    "examples/test4.hs":-    "examples/test5.hs":+    "-XDataKinds":+    "-XConstraintKinds":+    "-XDataKinds":+    "-XFlexibleContexts":+    "-XFlexibleInstances":+    "-XFunctionalDependencies":+    "-XGADTs":+    "-XKindSignatures":+    "-XMultiParamTypeClasses":+    "-XScopedTypeVariables":+    "-XTypeFamilies":+    "-XTypeOperators":+    "-XViewPatterns":     "src/RlangQQ.hs":     []
examples/Makefile view
@@ -1,19 +1,16 @@ # build and test all examples # --SHELL = bash- default: test6.html test7.html 	cd ../; runghc examples/runexamples.hs-	runghc examples/tests.hs+	cd ../; runghc examples/tests.hs 	ghc -O2 romberg.hs; ./romberg  %.html: %.md 	pandoc -s $< -o "$@"  %.md: %.Rmd-	R --no-save <<< 'library(knitr); knit("$<")'+	R --no-save -e 'library(knitr); knit("$<")'  %.Rmd.html: %.Rmd 	vim -c ":TOhtml" -c ":wqall" $<@@ -28,6 +25,6 @@ 		romberg_Double.pdf romberg_Float.pdf  installdeps:-	R --no-save <<< 'install.packages(c("knitr", "lattice", "reshape", "ggplot2", "lattice"))'+	R --no-save -e 'install.packages(c("knitr", "lattice", "reshape", "ggplot2", "lattice"))' 	cabal install lens numbers hspec 
examples/tests.hs view
@@ -1,3 +1,5 @@+{-# OPTIONS_GHC -F -pgmF HListPP #-}+{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE DataKinds, PolyKinds, FlexibleContexts, TemplateHaskell, QuasiQuotes #-}@@ -12,10 +14,6 @@ import Control.Monad import qualified Data.Vector as V -makeLabelable "x y z"--inRecL = hLens' (Label :: Label "inRec")- inRec = [pun| x y z |] where     x = "xlabel"     y,z :: [Double]@@ -26,8 +24,6 @@ main = hspec $ describe "rlangqq" $ do   it "can read a tsv file" $ do       [pun| x@(a b) s |] <- [r|-        # find the file whether we runghc tests.hs-        # runghc examples/tests.hs         fname <- c(Sys.glob('*.tsv'), Sys.glob('examples/*.tsv'))[1]         hs_x <- as.list(read.delim(fname, sep=' '))         hs_s <- as.numeric(with(hs_x, t(a) %*% b))@@ -39,8 +35,7 @@        o <- [r| print(hs_inRec) # should be unnecessary                hs_inRec <- within(hs_inRec, y <- y + z) |]-      let inR = hLens' (Label :: Label "inRec")-      (o ^.inR.y) `shouldBe` zipWith (+) (inRec^.y) (inRec^.z)+      (o ^. `inRec . `y) `shouldBe` zipWith (+) (inRec^.`y) (inRec^.`z)      it "accumulates when variables are ch_" $ do         w <- newRChan@@ -49,20 +44,20 @@             hs_inRec <- within(hs_inRec, y <- y + z + ch_w) |]          out <- forM [1,2,3,4 :: Double] $ \n -> do-                sendRcv w n <&> view (inRecL . y)+                sendRcv w n <&> view (`inRec . `y)         out `shouldBe`           tail (scanl-                    (\ accum n -> map (+n) $ zipWith (+) (inRec^.z) accum)-                    (inRec^.y)+                    (\ accum n -> map (+n) $ zipWith (+) (inRec^. `z) accum)+                    (inRec^. `y)                     [1 .. 4])    it "repeats when variables are not ch_" $ do       out <- forM [1,2,3,4 :: Double] $ \n -> do           [r| print(hs_inRec) # this shouldn't be necessary to force INOUT               hs_inRec <- within(hs_inRec, y <- y + z + hs_n) |]-            <&> view (inRecL . y)+            <&> view (`inRec . `y)       out `shouldBe`-       map (\n -> map (+n) (zipWith (+) (inRec^.y) (inRec^.z))) [1 .. 4]+       map (\n -> map (+n) (zipWith (+) (inRec^.`y) (inRec^.`z))) [1 .. 4]        it "interpolates haskell expressions" $ do         ys <- forM [1,2,3,4 :: Double] $ \n -> do@@ -70,7 +65,7 @@                         print(hs_inRec)                         hs_inRec <- within(hs_inRec, y <- y + z + $(n+1)  ) |]             return y-        ys `shouldBe` map (\n -> map (+(1+n)) (zipWith (+) (inRec^.y) (inRec^.z))) [1 .. 4]+        ys `shouldBe` map (\n -> map (+(1+n)) (zipWith (+) (inRec^.`y) (inRec^.`z))) [1 .. 4]    it "can make a plot where you ask it to" $ do       let x = [0 .. 10  :: Double]@@ -85,3 +80,16 @@           dev.off()           |]       doesFileExist "testplot.png" `shouldReturn` True+++  it "does positional arguments" $ do+      let n, m :: Integer+          n = 5+          m = 6+      nm <- [r| hs_x <- hs_1 * $(2)  |] n m+      nm `shouldBe` (`x .==. (n*m) .*. emptyRecord)++      mm <- [r| hs_x <- hs_2 * hs_2 |] n m+      mm `shouldBe` (`x .==. (m*m) .*. emptyRecord)++
− src/HListExtras.hs
@@ -1,14 +0,0 @@-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE UndecidableInstances #-}--module HListExtras where-import Data.HList.CommonMain---data FApply = FApply-instance (ApplyAB f a b, ab ~ (a -> b)) =>  ApplyAB FApply f ab where-    applyAB _ = applyAB--
src/RlangQQ/Binary.hs view
@@ -30,6 +30,7 @@      module Data.HList.CommonMain, ) where +import Control.Lens import System.Process import Unsafe.Coerce import Control.Applicative@@ -51,6 +52,7 @@ import Data.Binary.Builder import Data.Binary.Put import qualified Data.Binary+import Data.Binary.IEEE754 (doubleToWord, wordToDouble)  import qualified Data.Text as T import Data.Text.Encoding as E@@ -68,16 +70,11 @@  import qualified Codec.Compression.GZip as GZip -import HListExtras -data FLVPair = FLVPair-instance (Tagged l a ~ b) => ApplyAB FLVPair a b where-    applyAB FLVPair x = Tagged x---- this should not be necessary-type family UnHMapFLVPair (a :: [*]) :: [*]-type instance UnHMapFLVPair (Tagged l a ': as) = a ': UnHMapFLVPair as-type instance UnHMapFLVPair '[] = '[]+-- | labels are stored with the variables here. compare with the instance for 'Record' / 'LST' which collects+-- the labels and saves them as an attribute called \"names\"+newtype RDA a = RDA (HList a)+makeWrapped ''RDA  -- | this seems to be a magic number. Corresponds to R 3.0.1 putVersion = put (262153 :: Int32)@@ -94,8 +91,8 @@  -- | the binary instance of Double produces 25 bytes, not the 8 bytes for ieee754 -- perhaps alternatives to binary do better (bytes, cereal etc).-putDouble = put . (unsafeCoerce :: Double -> Int64)-getDouble = fmap (unsafeCoerce :: Int64 -> Double) get+putDouble = put . doubleToWord+getDouble = fmap wordToDouble get  getVectorDouble = do   14 <- get :: Get Int32@@ -194,20 +191,18 @@         hFoldr (HSeq FToRDS) (return () :: Put) xs :: Put         put (254::Int32) -type RDSHLIST2 b bs' l = (HSequence Get b l, HSequence ((->) ()) bs' b,-      HReplicate (HLength l) FFromRDS,-      HMapAux FApply (HReplicateR (HLength l) FFromRDS) bs',-      SameLength (HReplicateR (HLength l) FFromRDS) bs',-      SameLength bs' (HReplicateR (HLength l) FFromRDS),-      HNat2Integral (HLength l))+type RDSHLIST2 b l = (HSequence Get b l,+      HReplicateF (HLength l) FFromRDS () b,+      HNat2Integral (HLength l),+      HLengthEq l (HLength l)) -instance (RDSHLIST2 ___ __ l) => FromRDS (LST l) where+instance (RDSHLIST2 __ l) => FromRDS (LST l) where     fromRDS = withSelf $ \(self) -> do         531 <- get :: Get Int32         let len = hNat2Integral (hLength self)          len2 <- get :: Get Int32         when (len /= len2) $ error $ "fromRDS expected length: " ++ show len ++ " rds file has length: " ++ show len2-        r <- hSequence (hSequence (hMap FApply $ hReplicate (hLength self) FFromRDS) ())+        r <- hSequence $ hReplicateF (hLength self) FFromRDS ()         254 <- get :: Get Int32         return (LST r)       where@@ -225,33 +220,24 @@ instance ToRDSRecord __ ___ xs => ToRDS (Record xs) where     toRDS (Record xs) = toRDS $ LST $                 recordValues (Record xs) `hAppend`-                (ListStart `HCons` (Label :: Label "names") .=. (recordLabelsString (error "recLabs" :: Proxy (RecordLabels xs))) `HCons` HNil)+                (ListStart `HCons` (Label :: Label "names") .=. (recordLabelsString (Proxy :: Proxy (LabelsOf xs))) `HCons` HNil)  type ToRDSRecord __ ___ xs = (RDSHLIST __ ___, ToRDS (LST ___),             RecordValues xs,             HList ___ ~ (HList (RecordValuesR xs) `HAppendR` HList '[ListStart, Tagged "names" [String]]),-            RecordLabelsString (RecordLabels xs),+            RecordLabelsString (LabelsOf xs),             HAppend (HList (RecordValuesR xs)) (HList '[ ListStart, Tagged "names" [String]]))    -- | this signature shouldn't be necessary... it just repeats all the -- functions called-type FromRDSRec a b as' as'2 bs' = (HSequence Get b as',-                HSequence ((->) ()) a b,-                HMapAux FLVPair as' bs',-                SameLength as' bs',-                SameLength bs' as',--                HMapAux FApply as'2 a,-                SameLength as'2 a,-                SameLength a as'2,--                HMapOut (HComp FShowLabel FLabelLVPair) bs' String,-                RecordLabelsString (RecordLabels bs'),-                HNat2Integral (HLength bs'),-                HReplicate (HLength bs') FFromRDS,-                HReplicateR (HLength bs')FFromRDS ~ as'2)+type FromRDSRec a c = (+                HReplicateF (HLength c) FFromRDS () a,+                HSequence Get a (RecordValuesR c),+                Unlabeled' c,+                RecordLabelsString (LabelsOf c),+                HNat2Integral (HLength c))  {- | R lists become HList records. @list(x=1,y='b')@ parses to something like@@ -265,53 +251,40 @@ You have to get the result type right (ie. @Record [Tagged \"x\" Double, Tagged \"y\" String]@) for things to parse -}-instance FromRDSRec a b as' as'2 bs' => FromRDS (Record bs') where+instance FromRDSRec b d => FromRDS (Record d) where     fromRDS = do         531 <- get :: Get Int32-        let len = hNat2Integral (Proxy :: Proxy (HLength bs'))+        let lenN = Proxy :: Proxy (HLength d)+            len = hNat2Integral lenN         len2 <- get :: Get Int32         when (len /= len2) $ error $ "fromRDS expected length: " ++ show len ++ " rds file has length: " ++ show len2 -        r <- hSequence-                (hSequence-                    (hMap FApply-                        (hReplicate (Proxy :: Proxy (HLength bs')) FFromRDS) )-                    ())+        c <- hSequence (hReplicateF lenN FFromRDS ())+         getListHdr         "names" <- getString         names :: [String] <- fromRDS -        let names' = recordLabelsString (error "recLabs" :: Proxy (RecordLabels bs'))+        let names' = recordLabelsString (Proxy :: Proxy (LabelsOf d))          unless (names == names') $ error $ "fromRDS expected names( ): " ++ show names'                     ++ " rds file has names attribute : " ++ show names          254 <- get :: Get Int32-        return (Record (hMap FLVPair (r :: HList as') :: HList bs'))-        -- this hMap1 can't be replaced by hMap?+        return (c ^. from unlabeled) -class RecordLabelsString (a :: [Symbol]) where+class RecordLabelsString (a :: [*]) where     recordLabelsString :: Proxy a -> [String]  instance RecordLabelsString '[] where     recordLabelsString _ = []  instance (ShowLabel x, RecordLabelsString xs)-        => RecordLabelsString (x ': xs) where+        => RecordLabelsString (Label x ': xs) where     recordLabelsString _ = showLabel (Label :: Label x) : recordLabelsString (Proxy :: Proxy xs) --- same as recordLabelsString, but less lazy-recLabs (Record xs) = hMapOut (HComp FShowLabel FLabelLVPair) xs -data FLabelLVPair = FLabelLVPair-instance(Tagged l a ~ x, y ~ Label l) => ApplyAB FLabelLVPair x y where-    applyAB FLabelLVPair _ = (Label :: Label l) -data FShowLabel = FShowLabel-instance (string ~ String, ShowLabel l, ll ~ Label l) => ApplyAB FShowLabel ll string-    where applyAB _ = showLabel-- instance ToRDS [Double] where     toRDS = toRDS . V.fromList @@ -387,7 +360,8 @@         putVersion  getListHdr = do-        [1026, 1, 262153] <- replicateM 3 (get :: Get Int32)+        [1026, 1] <- replicateM 2 (get :: Get Int32)+        _ <- getVersion         return ()  @@ -407,10 +381,6 @@         x <- fromRDS         return (Tagged x) --- | labels are stored with the variables here. compare with the instance for 'Record' / 'LST' which collects--- the labels and saves them as an attribute called \"names\"-newtype RDA a = RDA (HList a)- -- | internal instance forall rs l2 t. (ToRDS t, ToRDS (RDA rs), ShowLabel l2) => ToRDS (RDA (Tagged l2 t ': rs)) where     toRDS (RDA (x `HCons` xs)) = do@@ -633,23 +603,22 @@  > Record '[Tagged l1 (Tagged m1 x), Tagged l2 (Tagged m2 x)] -The outer labels (@l1@, @l2@) are the haskell-side. The inner labels+The outer labels (@l1@, @l2@) are those used on the haskell-side. The inner labels are the @m1@ @m2@ which are the names of the variables on the R side.   -}  --- why can't the __ type be inferred?-fromRDA :: forall __ r.  FromRDA __ r => B.ByteString -> Record r+fromRDA :: FromRDA r => B.ByteString -> Record r fromRDA x = ( $ GZip.decompress x) $ runGet $ do     let hdr =  "RDX2\nX\n"     hdr' <- fmap (BS.toString) $ getByteString (BS.length (BS.fromString hdr))     unless (hdr == hdr') $ fail "wrong header"     [{- 2 , 196609, 131840 -} _, _, _ :: Int32 ] <- replicateM 3 get-    fmap (\(RDA a) -> Record (hMap FLVPair (a::HList __) )) fromRDS+    fromRDS <&> view ( _Wrapping RDA . from unlabeled) -type FromRDA a r = (HMapCxt FLVPair (HList a) (HList r) a r, FromRDS (RDA a))+type FromRDA r = (Unlabeled' r, FromRDS (RDA (RecordValuesR r)))  -- * tests 
− src/RlangQQ/FN.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE MultiParamTypeClasses #-}--- | 'hMap' 'FN' drops the inner Tagged, which was--- just used to keep track of the variable name on the--- R side.------ it could be replaced by unsafeCoerce with the--- right type signature-module RlangQQ.FN where-import Data.HList.CommonMain-import GHC.TypeLits-data FN = FN--instance (a ~ (Tagged (t :: k) (Tagged (t2::k) x)), b ~Tagged t x) => ApplyAB FN a b where-    applyAB _ (Tagged (Tagged x)) = Tagged x--data NoLabel = NoLabel-instance (la ~ Tagged "" a) => ApplyAB NoLabel a la where-    applyAB _ x = Tagged x-
src/RlangQQ/Internal.hs view
@@ -1,10 +1,11 @@-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TemplateHaskell, NoCPP #-} module RlangQQ.Internal where  import System.IO.Temp import System.IO  import Control.Applicative+import Data.Char import Data.List import Data.Maybe import Data.Monoid@@ -16,18 +17,22 @@ import System.Process import Text.Printf import Text.Trifecta+import Text.Read (readMaybe)  import qualified Data.ByteString.Lazy.UTF8 as B import qualified Data.ByteString.Lazy as B import qualified Data.ByteString.Lazy import qualified Data.ByteString.Lazy.Char8 as B8 +import qualified Data.Digest.Pure.SHA as SHA+ import Control.Monad.State import Control.Monad.Trans.Maybe import Data.Generics import qualified Data.Traversable as T import qualified Data.Map as M import Data.Foldable (foldMap)+import qualified Data.Set as S  import System.FilePath @@ -35,13 +40,14 @@  import RlangQQ.Binary import RlangQQ.Antiquote-import RlangQQ.FN -- import RlangQQ.ParseKnitted  import Control.Concurrent.Chan import Control.Concurrent.MVar import Control.Concurrent +import Control.Lens hiding (noneOf)+ import System.IO.Unsafe import Data.IORef @@ -49,25 +55,33 @@  -- | going via binary serialization (classes from "RlangQQ.Binary"). This is used in 'RlangQQ.r' quoteRExpression2 i returnChan str0 = do-    let rawFile, mdFile, rmdFile, inputFile, inputFile2, outputFile, figPath :: String-        rawFile    = printf "Rtmp/raw%d.R" (i :: Int)-        rmdFile    = printf "Rtmp/raw%d.Rmd" i-        rmdFile2   = printf "Rtmp/raw%d_.Rmd" i-        mdFile     = printf "Rtmp/raw%d.md" i-        figPath    = printf "Rtmp/fig%d/" i-        inputFile  = printf "Rtmp/%d_hs.rdx" i-        inputFile2 = printf "Rtmp/%d_hs2.rdx" i-        outputFile = printf "Rtmp/%d_r.rdx" i+    let str0Hash = take 8 $ SHA.showDigest (SHA.sha1 (B8.pack str0))+        rawFile, mdFile, rmdFile, inputFile, inputFile2, outputFile,+          figPath :: String+        rawFile    = printf "Rtmp/%s/raw%d.R" str0Hash (i :: Int)+        rmdFile    = printf "Rtmp/%s/raw%d.Rmd" str0Hash i+        rmdFile2   = printf "Rtmp/%s/raw%d_.Rmd" str0Hash i+        mdFile     = printf "Rtmp/%s/raw%d.md" str0Hash i+        figPath    = printf "Rtmp/%s/fig%d/" str0Hash i+        inputFile  = printf "Rtmp/%s/%d_hs.rdx" str0Hash i+        inputFile2 = printf "Rtmp/%s/%d_hs2.rdx" str0Hash i+        outputFile = printf "Rtmp/%s/%d_r.rdx" str0Hash i -        -- the print('') is to fix a bug that somehow drops the first-        -- expression sent to R-        (knitrHdr, withRawFile -> (("setwd('../');"++) -> str, addAntiquotes))+        (knitrHdr, withRawFile -> (("setwd('../../'); getwd();"++) -> str, addAntiquotes))             = splitKnitrHdr str0     let inRmdChunk s = unlines ["```{r " ++ knitrHdr ++ "}", s, "```"]      variables <- runIO $ do-        t <- getDataFileName "Tree.R"-        createDirectoryIfMissing False "Rtmp"+        t <- do+          t1 <- getDataFileName "Tree.R"+          b <- doesFileExist t1+          -- for the benefit of "cabal test"+          -- which does not set the environment variable+          -- Rlang_QQ_datadir=rsrc, and you don't necessarily+          -- have Tree.R installed in the ~/.cabal/... yet+          return $ if b then t1 else "rsrc/Tree.R"++        createDirectoryIfMissing True ("Rtmp/" ++ str0Hash)         writeFile rawFile str         writeFile rmdFile (inRmdChunk str)         rt <- readProcess "R" ["--no-save","--quiet"]@@ -78,9 +92,6 @@                 print a                 error "parse failure" -    -- reify doesn't work well enough-    -- (chanVars, mVars, M.fromList -> variables) <- classifyByConT (M.toList variables)-     (variables, chanVars) <- return $ M.partitionWithKey (\k _ -> "hs_" `isPrefixOf` k) variables      let@@ -120,8 +131,8 @@         sampOutput' :: (String -> ExpQ) -> ExpQ         sampOutput' addLabels = mkHList                 [ [| $(addLabels x) $(case intent of-                                    Out -> [| undefined |] -- no input value whose-                                                           -- type should unify with+                                    Out -> [| error ("RlangQQ.Internal.sampOutput" +++                                                     " should not be evaluated") |]                                     _ -> var x ) |]                      | (x, intent) <- M.toList variables, notIn intent ]@@ -133,16 +144,18 @@          readOutputFile :: ExpQ         readOutputFile = [|-            let mapSnd (Record x) = Record (hMap FN x)+            let -- Record '[Tagged "x" (Tagged "x1" a)] -> Record '[Tagged "x" a]+                dropInnerTagged x = over unlabeled (^. to Record . unlabeled) x                 fixTy x = x `asTypeOf` Record $sampOutput-                fixTy2 x = x `asTypeOf` Record $sampOutput2             in do               cts <- B.readFile outputFile               -- lazy IO makes for confusings: possibly better to switch               -- over to strict BS instead of this               Data.ByteString.Lazy.length cts `seq` return ()-              return . fixTy2 . mapSnd . fixTy $ fromRDA cts  |] +              -- to stop ghc-7.6 from having a type error:+              return . $(varE 'dropInnerTagged) . fixTy $ fromRDA cts |]+         outVars :: [String]         outVars = [ s  | (s, intent) <- M.toList variables                         ++ M.toList chanVars {- necessary? -}, notIn intent ]@@ -206,9 +219,9 @@                                  ov output                                 $(whenQ returnChan-                                    ([| (`writeChan` output) |] `appE` [| chOut |])-                                    -- should be   writeChan chOut output-                                    -- but that doesn't typecheck here...+                                    [| $(varE 'writeChan) chOut output |]+                                    -- rewrite to: [| writeChan chOut output |]+                                    -- when ghc-7.6 support is dropped                                     )                                 |])             return chOut@@ -216,16 +229,23 @@      runIO $ writeFile rmdFile2 rmd2Content -    addAntiquotes [| do+    let positionalVariablesIx :: M.Map Int (S.Set String)+        positionalVariablesIx = M.fromListWith (<>)+                        $ mapMaybe (\ k -> do+                              n <- readMaybe =<< msum (map (`stripPrefix` k) prefixes)+                              return (n, S.singleton k))+                        $ [ v  | (v, intent) <- M.toList variables,+                                  intent `elem` [In,InOut] ]++    addLambda positionalVariablesIx $ addAntiquotes [| do         {- already done, but Rtmp could have moved-           since compile time -}-        createDirectoryIfMissing False "Rtmp"-        do-            f <- doesFileExist rmdFile2-            unless f $ writeFile rmdFile2 rmd2Content+           since compile time, or another RlangQQ could+           have overwritten the file -}+        createDirectoryIfMissing True ("Rtmp" </> str0Hash)+        writeFile rmdFile2 rmd2Content          $writeInputFile-        $(if M.size chanVars == 0 then [| do+        $(if M.null chanVars then [| do                 $runRNoChan                 $( whenOutVars readOutputFile) |]             else runRChan)@@ -254,6 +274,8 @@             (\(a,b,c) -> (a,b)) $             foldr (\ chunk ~( str, ef, i) ->                 case chunk of+                    Left (LitE (IntegerL p)) -> ("hs_" ++ show p ++ " " ++ str,+                                                  ef, i)                     Left x ->                         let v = "hs_interp" ++  show i in                         ( concat [v, " ", str],@@ -268,6 +290,31 @@                 parsed  +addLambda :: M.Map Int (S.Set String) -> ExpQ -> ExpQ+addLambda ps xp+    | Just ((pMax,_), _ ) <- M.maxViewWithKey ps = do+        let allPS = M.fromList [ (n,()) | n <- [1 .. pMax] ]+        case M.keys $ ps M.\\ allPS of+            [] -> return ()+            extra -> reportWarning ("Unexpected positional arguments " ++ show extra)++        case M.keys $ allPS M.\\ ps of+            [] -> return ()+            unused -> reportWarning ("Positional argument not used " ++ show unused)++        case  [ p0 |  p0 <- M.elems ps,+                      S.size p0 > 1 ] of+            [] -> return ()+            duplicates -> reportError ("Positional argument types must be the same " ++ show duplicates )++        lamE [ case M.lookup n ps of+                   Just (S.toList -> [e]) -> varP (mkName e)+                   Nothing -> wildP+                | n <- [1 .. pMax] ] xp+    | otherwise = xp+++ -- ** utility functions -- | go from the variable name used on the R-side to the one in the haskell side dropHS x = fromMaybe x (foldMap stripPrefix prefixes x)@@ -279,7 +326,9 @@ label x = [| Label :: Label $(litT (strTyLit (dropHS x))) |] label' x = [| Label :: Label $(litT (strTyLit x)) |] -var x = varE (mkName (dropHS x))+var x = varE $ mkName $ case dropHS x of+          x' | all isDigit x' -> x+             | otherwise -> x'  mkHList :: [ExpQ] -> ExpQ mkHList = foldl (\ b a -> [| $a .*. $b |]) [| HNil |]@@ -359,25 +408,6 @@     toList :: Tree a -> [Tree a]     toList a = a : concatMap toList (subForest a) --- | this reify fails most of the time, since the type isn't--- available in a quasiquote (run in the renamer) for things--- declared in the same file.-getConTOf:: String -> Q (Maybe Name)-getConTOf x = runMaybeT $ do-    n <- MaybeT $ lookupValueName (dropHS x)-    VarI _ (AppT (ConT n) _) _ _ <- MaybeT $ (Just `fmap` reify n) `recover` return Nothing-    return n--classifyByConT =-    foldr (\ el lists -> do-            ~(x,y,z) <- lists-            ct <- getConTOf (fst el)-            case ct of-                Just ty | ty == ''MVar -> return (x, el : y, z)-                        | ty == ''Chan -> return (el : x, y, z)-                _ -> return (x,y, el : z)-                )-        (return ([],[],[]))   -- ** tests
src/RlangQQ/MakeRecord.hs view
@@ -2,28 +2,17 @@ module RlangQQ.MakeRecord where  import GHC.TypeLits -- prevents a panic lookupVers2 <<details unavailable>> with ghc 7.6. Fixed later probably from #7502-import Control.Monad.State-import Control.Monad.Identity import Data.HList.CommonMain-import HListExtras+import Control.Lens + -- | convert a haskell list into a record with labels all of type \"\". The length -- of the list is decided by the (type of the) first argument which is a 'HNat'-listToRecN :: ListToRecN __ (n :: HNat) x r => Proxy n -> [x] -> Record r-listToRecN n xs = Record $ hMap NoLabel $ flip evalState xs $ hSequence $ hReplicate n comp-    where comp = do-                x : xs' <- get-                return () :: State [x] ()-                put (xs' `asTypeOf` xs)-                return (x `asTypeOf` head xs)--type ListToRecN __ (n :: HNat) x r = (HReplicate n (StateT [x] Identity x),-    HSequence (StateT [x] Identity) (HReplicateR n (StateT [x] Identity x)) __,-    HMapCxt NoLabel (HList __) (HList r) __ r)----data NoLabel = NoLabel-instance (Tagged "" a ~ la) => ApplyAB NoLabel a la where-    applyAB _ x = Tagged x+--+-- > listToRecN :: _ => Proxy (n :: HNat) -> [x] -> Record (HReplicateR n (Tagged "" x))+listToRecN n xs = maybe (error msg) (`asTypeOf` es)+                  $ xs ^? listAsHList . from unlabeled +  where es = (undefined :: Proxy n -> [x] -> Record (HReplicateR n (Tagged "" x)))+                n xs+        msg = "RlangQQ.listToRecN too few elements"