------------------------------------------------------------------------------- {- LANGUAGE CPP #-} #define USE_TRACE 1 #define SEQHARN_WRAP_PARENT 1 ------------------------------------------------------------------------------- #if USE_SOP {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ConstraintKinds #-} #if __GLASGOW_HASKELL__ < 708 {-# LANGUAGE GADTs #-} #endif {-# LANGUAGE TemplateHaskell #-} #else {-# LANGUAGE BangPatterns #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleContexts #-} {- LANGUAGE MultiParamTypeClasses #-} {- LANGUAGE Rank2Types #-} #endif {-# LANGUAGE ScopedTypeVariables #-} {- LANGUAGE AllowAmbiguousTypes #-} ------------------------------------------------------------------------------- -- | -- Module : Control.DeepSeq.Bounded.Generic.GSeqable -- Copyright : Andrew G. Seniuk 2014-2015 -- License : BSD-style (see the LICENSE file) -- -- Maintainer : Andrew Seniuk -- Stability : provisional -- Portability : GHC -- -- Generic function version of (via ). -- -- Probably, a "GHC.Generics" variant would also be possible. -- -- This metaboilerplate is standard for using the generic deriving -- facilities of . -- Consider -- for a turnkey solution. -- -- > {-# LANGUAGE TemplateHaskell #-} -- > {-# LANGUAGE DataKinds #-} -- > {-# LANGUAGE TypeFamilies #-} -- > {-# LANGUAGE DeriveDataTypeable #-} -- > {-# LANGUAGE GADTs #-} -- for GHC < 7.8 (== 7.6.3) -- > -- > import Generics.SOP.TH -- > import Control.DeepSeq.Bounded.Seqable -- > -- > data TA = A1 TB TA | A2 -- > data TB = B1 Int | B2 TA -- > -- > deriveGeneric ''TA -- > deriveGeneric ''TB -- > -- > main = return $! force_ Propagate (A1 (force_ Propagate (B2 undefined)) A2) ------------------------------------------------------------------------------- module Control.DeepSeq.Bounded.Generic.GSeqable ( #if USE_SOP grnf_ , gseq_ , gforce_ #else genericSeq_ -- , genericSeq_V1 #endif , seqharn ) where ------------------------------------------------------------------------------- import Control.DeepSeq.Bounded.Pattern ( SeqNode(..) ) --import Control.DeepSeq.Bounded.Seqable ( SeqNode(..) ) #if USE_SOP import Generics.SOP --import Generics.SOP.TH -- not here, but rather in the module needing to generically derive an Seqable instance #else import GHC.Generics #endif import Control.Parallel ( par ) import Data.Typeable ( typeOf ) import Data.Typeable ( Typeable ) import Debug.Trace ( trace ) ------------------------------------------------------------------------------- #if USE_SOP gseq_ :: Generic a => SeqNode -> a -> b -> b gseq_ Insulate a b = b gseq_ k a b = grnf_ k a `seq` b -- sic! both Propagate and Spark gforce_ :: Generic a => SeqNode -> a -> a gforce_ Insulate a = a gforce_ k a = grnf_ k a `seq` a -- sic! both Propagate and Spark grnf_ :: Generic a => SeqNode -> a -> () grnf_ Insulate x = () grnf_ k x = grnf_S k (from x) grnf_S :: SeqNode -> SOP I xss -> () #if USE_PAR_SEQABLE grnf_S Propagate (SOP (Z xs)) = grnf_P xs `seq` () grnf_S {-Spark-}_ (SOP (Z xs)) = grnf_P xs `par` () #else grnf_S {-Propagate-}_ (SOP (Z xs)) = grnf_P xs `seq` () #endif grnf_S k (SOP (S xss)) = grnf_S k (SOP xss) grnf_P :: NP I xs -> () grnf_P Nil = () grnf_P (I x :* xs) = x `seq` grnf_P xs ------------------------------------------------------------------------------- #if 1 -- | @'seqharn' x@ is semantically the same as @x@, except its -- strictness, parallellism, etc. can be tweaked dynamically... -- -- > seqharn = to . hliftA (gforce_ Insulate) . from -- -- /I can see how this would be useful at compile-time, but how can we use this if seqharn only runs post-compilation? Or is it just analogous to forcep?.../ -- -- /Also: How exactly to/ dynamically configure /this?.../ seqharn :: Generic a => a -> a -- hliftA f xs = hpure (fn f) ` hap ` xs seqharn = to . hliftA (gforce_ Insulate) . from --seqharn x = to $ hliftA (gforce_ Insulate) $ from x --seqharn x = to $ hpure (fn $ gforce_ Insulate) `hap` from x --seqharn x = to (hap (hpure (fn (gforce_ Insulate))) (from x)) --seqharn x = to $ hap (hpure (fn $ gforce_ Insulate)) $ from x #if 0 -- | The 'PatNode's of the 'Pattern' argument carry 'SeqNode' -- programmability information in the 'seqNode' field. -- The 'PatNode' must be 'WR' for interior nodes and 'WS' for leaves, -- such as returned by 'mkPat'. -- Pattern match is an error. configure_seqharn :: Generic a => Pattern -> SeqNode a -> SeqNode a configure_seqharn (Node pn cs) (SeqNode k x) | WI{} <- pn = ... #endif -- No joy. -- What if just replace every node with a SeqNode'? -- But that's what I'm trying to do... #if 0 data SeqNode' a = Insulate' a --- | Conduct' a | Propagate' a #if USE_PAR_SEQABLE | Spark' a #endif deriving ( Eq, Ord ) unSeqNode' :: SeqNode' a -> a unSeqNode' (Insulate' x) = x unSeqNode' (Propagate' x) = x #if USE_PAR_SEQABLE unSeqNode' (Spark' x) = x #endif #if 1 -- Yet here it is in SYB: ... oops, no, only if -- the user passes the generic function in (familiar -- quandry, esp from sai-shape-syb)... testboo :: Data a => GenericT -> a -> SeqNode' a testboo fg x = everywhere fg x where fg :: ... #else -- XXX Maybe this just isn't possible (and fortunately the function -- approach even works!...) -- it seems like I want to say here -- that SeqNode' a is equivalent to a as a type, but that's not -- correct -- they will be equivalent, in some sense, as VALUES -- (in a given term context), but they are not equivalent as types. -- In particular, SeqNode' a has arity 1 for every constructor, but -- a itself might be of any arity. -- Still maybe there's some way ... the AST makes sense, anyway... -- If we have a function a -> a, we can lift it to SeqNode' a -> SeqNode' a. -- Or we can us unSeqNode'?... -------- -- Note that TypeRep (returned by typeOf) does have an Eq instance. -- However, I think the problem of supplying lists of TypeRep -- instead of String type names, for stoptys argument, was -- a deterrent... --testboo :: forall a. (SeqNode' a ~ a, Generic a) => testboo :: Generic a => [String] -> a -> SeqNode' a --testboo :: (Typeable a, Generic a) => [String] -> a -> SeqNode' a --testboo :: (Typeable a, Generic a, All2 Typeable (Code a)) => [String] -> a -> SeqNode' a testboo stoptys x = x'' where -- proxy = Proxy :: a -- tstr = show $ typeOf x -- x' = to $ hpure (fn (testboo stoptys)) `hap` from x -- x' = to $ hcliftA proxy (unSeqNode' . testboo stoptys) $ from x x' = to $ hliftA (testboo stoptys) $ from x --- x' = to $ hpure (I . fn . testboo stoptys . unI) `hap` from x --- x' = to $ hpure (fn $ I . testboo stoptys . unI) `hap` from x -- x' = to $ hpure (fn $ testboo stoptys) `hap` from x #if 0 x'' | elem tstr stoptys = Insulate' x' | otherwise = Propagate' x' #else x'' | True = Insulate' x | otherwise = Propagate' x #endif #endif #endif #else #if SEQHARN_WRAP_PARENT -- | @'seqharn' x@ is semantically the same as @x@, except its -- strictness, parallellism, etc. can be tweaked dynamically... seqharn :: Generic a => a -> a seqharn x = gforce_ Insulate (seqharnS (from x)) -- From the sum, select the alternative corresponding to the term node. -- This alternative is one of the constructors of the data type, -- with its arguments represented as a product. seqharnS :: SOP I xss -> a seqharnS (SOP (Z xs)) = seqharnP xs seqharnS (SOP (S xss)) = seqharnS (SOP xss) -- Traverse the constructor arguments of the product. seqharnP :: NP I xs -> a seqharnP Nil = () seqharnP (I x :* xs) = seqharn x `seq` seqharnP xs #else -- | @'seqharn' x@ is semantically the same as @x@, except its -- strictness, parallellism, etc. can be tweaked dynamically... seqharn :: Generic a => a -> a seqharn x = seqharnS (from x) -- From the sum, select the alternative corresponding to the term node. -- This alternative is one of the constructors of the data type, -- with its arguments represented as a product. seqharnS :: SOP I xss -> a seqharnS (SOP (Z xs)) = seqharnP xs seqharnS (SOP (S xss)) = seqharnS (SOP xss) -- Traverse the constructor arguments of the product. seqharnP :: NP I xs -> a seqharnP Nil = () seqharnP (I x :* xs) = (gforce_ Insulate (seqharn x)) `seq` seqharnP xs #endif #endif ------------------------------------------------------------------------------- #else #error "GSeqable: must use SOP for now..." #endif -------------------------------------------------------------------------------