--
-- (c) Susumu Katayama
--
\begin{code}
{-# OPTIONS -fglasgow-exts -XTemplateHaskell -cpp #-}
module MagicHaskeller(
-- * Re-exported modules
-- | This library implicitly re-exports the entities from
-- @module Language.Haskell.TH as TH@ and @module Data.Typeable@ from the Standard Hierarchical Library of Haskell.
-- Please refer to their documentations on types from them --- in this documentation, types from TH are all qualified and the only type used from @module Typeable@ is Typeable.Typeable. Other types you had never seen should be our internal representation.
module TH, module Typeable,
{- x ²¼¤ÎÊý¤ËThe program generators¤Ã¤Æ¤Î¤¬¤¢¤ë¤¿¤á¡¤confusing¤Ê¤Î¤Ç¡¥
-- * Program generators
ProgramGenerator, ProgGen, ProgGenSF, {- ProgGenSFIF, -} CutFree, CutFreeSF, ConstrL, ConstrLSF,
-}
-- * Setting up your synthesis
-- | Before synthesis, you have to define at least one program generator algorithm (or you may define one once and reuse it for later syntheses).
-- Other parameters are memoization depth and time out interval, which have default values.
-- You may elect either to set those values to the \'global variables\' using \'@set@*\' functions (i.e. functions whose names are prefixed by @set@), or hand them explicitly as parameters.
-- ** Class for program generator algorithms
-- | Please note that @ConstrL@ and @ConstrLSF@ are obsoleted and users are expected to use the 'constrL' option in 'Option'.
ProgramGenerator,
ProgGen, ProgGenSF, ProgGenXF,
-- ** Functions for creating your program generator algorithm
-- | You can set your primitives like, e.g., @'setPrimitives' $('p' [| ( (+) :: Int->Int->Int, 0 :: Int, \'A\', [] :: [a] ) |])@,
-- where the primitive set is consisted of @(+)@ specialized to type @Int->Int->Int@, @0@ specialized to type @Int@,
-- @ \'A\' @ which has monomorphic type @Char@, and @[]@ with polymorphic type @[a]@.
-- As primitive components one can include any variables and constructors within the scope.
-- However, because currently ad hoc polymorphism is not supported by this library, you may not write
-- @'setPrimitives' $('p' [| (+) :: Num a => a->a->a |])@.
-- Also, you have to specify the type unless you are using a primitive component whose type is monomorphic and instance of 'Data.Typeable.Typeable'
-- (just like when using the dynamic expression of Concurrent Clean), and thus
-- you may write @'setPrimitives' $('p' [| \'A\' |])@,
-- while you have to write @'setPrimitives' $('p' [| [] :: [a] |])@ instead of @'setPrimitives' $('p' [| [] |])@.
p, setPrimitives, mkPG, mkPGSF, setPG,
-- 'mkPG' and 'setPG' used to be called @mkMemo@ and @setMemo@ respectively (because the main ingredient of a program generator is a memoization table). ¤È¤¤¤¦¥³¥á¥ó¥È¤Ï¤½¤°¤ï¤Ê¤¯¤Ê¤Ã¤Æ¤¤¿¤Î¤Ç»ß¤á¤ë¡¥
-- | Older versions prohibited data types holding functions such as @[a->b]@, @(Int->Char, Bool)@, etc. just for efficiency reasons.
-- They are still available if you use 'mkMemo' and 'mkMemoSF' instead of 'mkPG' and 'mkPGSF' respectively, though actually this limitation does not affect the efficiency a lot.
-- (NB: recently I noticed that use of 'mkMemo' or 'mkMemoSF' might not improve the efficiency of generating lambda terms at all, though when I generated combinatory expressions it WAS necessary.
-- In fact, I mistakenly turned this limitation off, and 'mkMemo' and 'mkMemoSF' were equivalent to 'mkPG' and 'mkPGSF', but I did not notice that....)
mkMemo, mkMemoSF,
-- | @mkMemo075@ enables some more old good optimization options used until Version 0.7.5, including guess on the primitive functions.
-- It is for you if you prefer speed, but the result can be non-exhaustive if you use it with your own LibTH.hs.
-- Also, you need to use the prefixed |(->)| in order for the options to take effect. See LibTH.hs for examples.
mkPG075, mkMemo075,
-- | 'mkPGOpt' can be used along with its friends instead of 'mkPG' when the search should be fine-tuned.
mkPGOpt, Options, Opt(..), options, MemoType(..),
#ifdef HASKELLSRC
-- *** Alternative way to create your program generator algorithm
-- | 'load' and 'f' provides an alternative scheme to create program generator algorithms.
load, f,
#endif
-- ** Memoization depth
-- | NB: 'setDepth' will be obsoleted. It is provided for backward compatibility, but
-- not exactly compatible with the old one in that its result will not affect the behavior of 'everything', etc., which explicitly take a 'ProgramGenerator' as an argument.
-- Also, in the current implementation, the result of 'setDepth' will be overwritten by setPrimitives.
-- Use 'memodepth' option instead.
setDepth,
-- ** Time out
-- | NB: 'setTimeout' and 'unsetTimeout' will be obsoleted. They are provided for backward compatibility, but
-- not exactly compatible with the old ones in that their results will not affect the behavior of 'everything', etc., which explicitly take a 'ProgramGenerator' as an argument.
-- Also, in the current implementation, the result of 'setTimeout' and 'unsetTimeout' will be overwritten by setPrimitives.
-- Use 'timeout' option instead.
--
-- Because the library generates all the expressions including those with non-linear recursions, you should note that there exist some expressions which take extraordinarily long time. (Imagine a function that takes an integer n and increments 0 for 2^(2^n) times.)
-- For this reason, time out is taken after 0.02
-- second since each invocation of evaluation by default. This default behavior can
-- be overridden by the following functions.
setTimeout, unsetTimeout,
-- ** Defining functions automatically
-- | In this case \"automatically\" does not mean \"inductively\" but \"deductively using Template Haskell\";)
define, Everything, Filter, Every, EveryIO,
-- * Generating programs
-- | (There are many variants, but most of the functions here just filter 'everything' with the predicates you provide.)
--
-- Functions suffixed with \"F\" (like 'everythingF', etc.) are filtered versions, where their results are filtered to totally remove semantic duplications. In general they are equivalent to applying 'everyF' afterwards.
-- (Note that this is filtration AFTER the program generation, unlike the filtration by using 'ProgGenSF' is done DURING program generation.)
-- ** Quick start
findOne, printOne, printAll, printAllF, io2pred,
-- ** Incremental filtration
-- | Sometimes you may want to filter further after synthesis, because the predicate you previously provided did not specify
-- the function enough. The following functions can be used to filter expressions incrementally.
filterFirst, filterFirstF, filterThen, filterThenF,
-- ** Expression generators
-- | These functions generate all the expressions that have the type you provide.
getEverything, everything, everythingM, everythingIO, unifyable, matching, getEverythingF, everythingF, unifyableF, matchingF,
-- ** Utility to filter out equivalent expressions
everyF,
-- ** Unility to get one value easily
stripEvery,
-- ** Pretty printers
pprs, pprsIO, pprsIOn, lengths, lengthsIO, lengthsIOn, printQ,
-- * Internal data representation
-- | The following types are assigned to our internal data representations.
Primitive, HValue(HV),
-- other stuff which will not be documented by Haddock
unsafeCoerce#, {- unifyablePos, -} exprToTHExp, trToTHType, printAny, p1, Filtrable
) where
import Data.Generics(everywhere, mkT, Data)
import Data.Array.IArray
import MagicHaskeller.CoreLang
import Language.Haskell.TH as TH
#ifdef HASKELLSRC
import MagicHaskeller.ReadHsType(readHsTypeSigs)
#endif
import MagicHaskeller.TyConLib
import qualified Data.Map as Map
import Data.Char
import MagicHaskeller.Types as Types
import MagicHaskeller.ProgGen(ProgGen(PG))
import MagicHaskeller.ProgGenSF(ProgGenSF, PGSF)
-- import MagicHaskeller.ProgGenLF(ProgGenLF)
import MagicHaskeller.ProgGenXF(ProgGenXF)
import MagicHaskeller.ProgramGenerator
import MagicHaskeller.Options(Opt(..), options)
import Control.Monad.Search.Combinatorial -- This should all be exposed?
import Data.Typeable as Typeable
import System.IO.Unsafe(unsafePerformIO)
import Data.IORef
import GHC.Exts(unsafeCoerce#)
-- import Maybe(fromJust)
import System.IO
import System.Random(mkStdGen,StdGen)
import MagicHaskeller.MHTH
import MagicHaskeller.TimeOut
import MagicHaskeller.ReadTHType
import MagicHaskeller.ReadTypeRep(trToType, trToTHType)
import MagicHaskeller.MyDynamic
import qualified MagicHaskeller.PolyDynamic as PD
import MagicHaskeller.Expression
import MagicHaskeller.Classify
import MagicHaskeller.Classification(unsafeRandomTestFilter, Filtrable)
import MagicHaskeller.Instantiate(mkRandTrie)
import MagicHaskeller.MemoToFiles(MemoType(..))
\end{code}
\begin{code}
-- "MemoDeb" name should be hidden, or maybe I could rename it.
-- | 'define' eases use of this library by automating some function definitions. For example,
--
-- > $( define ''ProgGen "Foo" (p [| (1 :: Int, (+) :: Int -> Int -> Int) |]) )
--
-- is equivalent to
--
-- > memoFoo :: ProgGen
-- > memoFoo = mkPG (p [| (1 :: Int, (+) :: Int -> Int -> Int) |])
-- > everyFoo :: Everything
-- > everyFoo = everything memoFoo
-- > filterFoo :: Filter
-- > filterFoo pred = filterThen pred everyFoo
--
-- If you do not think this function reduces the number of your keystrokes a lot, you can do without it.
define :: TH.Name -> String -> TH.ExpQ -> TH.Q [TH.Dec]
define mn name pq = pq >>= \prims ->
return [ SigD (mkName ("memo"++name)) (ConT mn),
ValD (VarP (mkName ("memo"++name))) (NormalB (AppE (VarE (mkName "mkPG")) prims -- (VarE (mkName "prims"))
)) [],
SigD (mkName ("every"++name)) (ConT (mkName "Everything")),
ValD (VarP (mkName ("every"++name))) (NormalB (VarE (mkName "everything") `AppE` VarE (mkName ("memo"++name)))) [],
SigD (mkName ("filter"++name)) (ConT (mkName "Filter")),
ValD (VarP (mkName ("filter"++name))) (NormalB ((VarE (mkName "flip") `AppE` VarE (mkName "filterThen")) `AppE` VarE (mkName ("every"++name)))) [] ]
type Every a = [[(TH.Exp,a)]]
type EveryIO a = Int -- query depth
-> IO [(TH.Exp, a)]
type Everything = Typeable a => Every a
type Filter = Typeable a => (a->Bool) -> IO (Every a)
{- Because the left hand side is not TH.Exp, we cannot splice directly there.
initialize name depth prims = [d| { $(return (VarE (mkName ("memo"++name)))) = mkPG $prims;
$(return (VarE (mkName ("every"++name)))) :: Everything;
$(return (VarE (mkName ("every"++name)))) = everything $(return (LitE (NumL depth))) $(return (VarE (mkName ("memo"++name)))); } |]
-}
{- It is unlikely that mkMTH will ever be used, and seemingly my version of haddock dislikes TH.
-- One could write, for example, $(mkMTH $15 [| ( 0::Int, succ, nat_para, [] ) |] ),
-- but I am not sure if this style using mkMTH will ever be used.
mkMTH :: TH.ExpQ -> TH.ExpQ -> TH.ExpQ
mkMTH n leq = [| mkMD $n $(m leq) |]
-}
-- Rather, one could write, e.g.,
-- mkMD 15 $(p [| ( 0::Int, succ::Int->Int, nat_para, [] :: [a]) |] )
-- | 'p' is used to convert your primitive component set into the internal form.
p :: TH.ExpQ -- ^ Quote a tuple of primitive components here.
-> TH.ExpQ -- ^ This becomes @[Primitive]@ when spliced.
p eq = eq >>= \e -> case e of TupE es -> (return . ListE) =<< (mapM p1 es)
_ -> (return . ListE . return) =<< p1 e -- This default pattern should also be defined, because it takes two (or more) to tuple!
p1 :: TH.Exp -> TH.ExpQ
p1 se@(SigE e ty) = p1' se e ty
p1 e@(ConE name) = do DataConI _ ty _ _ <- reify name
p1' e e ty
p1 e@(VarE name) = do VarI _ ty _ _ <- reify name
p1' e e ty
p1 e = do ee <- expToExpExp e
return $ TupE [ AppE (ConE (mkName "HV")) (AppE (VarE (mkName "unsafeCoerce#")) e), ee, AppE (VarE (mkName "trToTHType")) (AppE (VarE (mkName "typeOf")) e)]
p1' se e ty = do ee <- expToExpExp e
et <- typeToExpType ty
return $ TupE [ AppE (ConE (mkName "HV")) (AppE (VarE (mkName "unsafeCoerce#")) se), ee, et]
-- nameToExpName :: TH.Name -> TH.Exp
-- nameToExpName = strToExpName . showName
-- strToExpName str = AppE (VarE (mkName "mkName")) (LitE (StringL str))
{- not used any longer
{- This should work in theory, but Language.Haskell.TH.pprint has a bug and it does not print parentheses....
pprintType (ForallT _ _ ty) = pprint ty
pprintType ty = pprint ty
-}
-- 'pprintType' is a workaround for the problem that @Language.Haskell.TH.pprint :: Type -> String@ does not print parentheses correctly.
-- (try @Language.Haskell.TH.runQ [t| (Int->Int)->Int |] >>= \e -> putStrLn (pprint e)@ in your copy of GHCi.)
-- The implementation here is not so pretty, but that's OK for my purposes. Also note that 'pprintType' ignores foralls.
pprintType (ForallT _ [] ty) = pprintType ty
pprintType (ForallT _ _ ty) = error "Type classes are not supported yet. Sorry...."
pprintType (VarT name) = pprint name
pprintType (ConT name) = pprint name
pprintType (TupleT n) = tuplename n
pprintType ArrowT = "(->)"
pprintType ListT = "[]"
pprintType (AppT t u) = '(' : pprintType t ++ ' ' : pprintType u ++ ")"
-- The problem of @Language.Haskell.TH.pprint :: Type -> String@ is now fixed at the darcs HEAD.
-}
primitivesp :: TyConLib -> [Primitive] -> [Typed [CoreExpr]]
primitivesp tcl ps
= zipWith (\ n (_,_,ty) -> [Primitive n] ::: thTypeToType tcl ty) [0..] ps
mkPG :: ProgramGenerator pg => [Primitive] -> pg
mkPG = mkPG' True
-- ^ 'mkPG' is defined as:
--
-- > mkPG prims = mkPGSF (mkStdGen 123456) (repeat 5) prims prims
mkMemo :: ProgramGenerator pg => [Primitive] -> pg
mkMemo = mkPG' False
mkPG' cont tups = case mkCommon options{contain=cont} tups of cmn -> mkTrie cmn (primitivesp (tcl cmn) tups)
-- | 'mkPGSF' and 'mkMemoSF' are provided mainly for backward compatibility. These functions are defined only for the 'ProgramGenerator's whose names end with @SF@ (i.e., generators with synergetic filtration).
-- For such generators, they are defined as:
--
-- > mkPGSF gen nrnds optups tups = mkPGOpt (options{primopt = Just optups, contain = True, stdgen = gen, nrands = nrnds}) tups
-- > mkMemoSF gen nrnds optups tups = mkPGOpt (options{primopt = Just optups, contain = False, stdgen = gen, nrands = nrnds}) tups
mkPGSF,mkMemoSF :: ProgramGenerator pg =>
StdGen
-> [Int] -- ^ number of random samples at each depth, for each type.
-> [Primitive]
-> [Primitive] -> pg
mkPGSF = mkPGSF' True
mkMemoSF = mkPGSF' False
mkPGSF' cont gen nrnds optups tups = mkPGOpt (options{primopt = Just optups, contain = cont, stdgen = gen, nrands = nrnds}) tups
-- Currently only the pg==ConstrLSF case makes sense. ¤Ã¤Æ¤Î¤Ï¡¤optups¤Î¤ß¤Ë´Ø¤¹¤ëÏäǡ¤rnds¤Ï´Ø·¸¤Ê¤¤¡¥
mkPG075 :: ProgramGenerator pg => [Primitive] -> pg
mkPG075 = mkPGOpt (options{primopt = Nothing, contain = True, guess = True})
mkMemo075 :: ProgramGenerator pg => [Primitive] -> pg
mkMemo075 = mkPGOpt (options{primopt = Nothing, contain = False, guess = True})
mkPGOpt :: ProgramGenerator pg => Options -> [Primitive] -> pg
mkPGOpt opt prims = case mkCommon opt prims of cmn -> mkTrieOpt cmn (primitivesp (tcl cmn) primsOpt) (primitivesp (tcl cmn) prims)
where primsOpt = case primopt opt of Nothing -> prims
Just po -> po
-- this can be moved to somewhere near Common is defined (currently ProgramGenerator.lhs), when 'Primitive' is moved to some more adequate place.
-- ¼ÂºÝProgramGenerator.lhs¤ÇPrimitive¤ò°·¤¨¤ì¤Ð¤â¤Ã¤Èñ½ã²½¤Ç¤¤ë¤Ï¤º¡¥
mkCommon :: Options -> [Primitive] -> Common
mkCommon opts prims = let
tyconlib = primitivesToTCL prims
optunit = forget opts
in Cmn {opt = optunit, tcl = tyconlib, vl = primitivesToVL tyconlib prims, rt = mkRandTrie (nrands opts) tyconlib (stdgen opts)}
-- | options for limiting the hypothesis space.
type Options = Opt [Primitive]
forget :: Opt a -> Opt ()
forget opt = case primopt opt of Nothing -> opt{primopt = Nothing}
Just _ -> opt{primopt = Just ()}
setPG :: ProgGen -> IO ()
setPG = writeIORef refmemodeb
-- | @setPrimitives@ creates a @ProgGen@ from the given set of primitives using the current set of options, and sets it as the current program generator.
-- It used to be equivalent to @setPG . mkPG@ which overwrites the options with the default, but it is not now.
setPrimitives :: [Primitive] -> IO ()
setPrimitives tups = do PG (x,y,cmn) <- readIORef refmemodeb
setPG $ mkPGOpt ((opt cmn){primopt=Nothing}) tups
-- setPrimitives tups = writeIORef refmemodeb (mkPG tups) -- This definition overwrites the old configuration.
#ifdef HASKELLSRC
-- | 'load' loads a component library file.
load :: FilePath
-> TH.ExpQ -- ^ This becomes @[Primitive]@ when spliced.
load fp = do str <- runIO $ readFile fp
f str
-- | f is supposed to be used by load, but not hidden.
f :: String -> TH.ExpQ
f = p . return . readHsTypeSigs
#endif
-- | 'setTimeout' sets the timeout in microseconds. Also, my implementation of timeout also catches inevitable exceptions like stack space overflow. Note that setting timeout makes the library referentially untransparent. (But currently @setTimeout 20000@ is the default!)
setTimeout :: Int -- ^ time in microseconds
-> IO ()
setTimeout n = do pto <- newPTO n
PG (x,y,cmn) <- readIORef refmemodeb
writeIORef refmemodeb $ PG (x,y,cmn{opt = (opt cmn){timeout=Just pto}})
-- | 'unsetTimeout' disables timeout. This is the safe choice.
unsetTimeout :: IO ()
unsetTimeout = do PG (x,y,cmn) <- readIORef refmemodeb
writeIORef refmemodeb $ PG (x,y,cmn{opt = (opt cmn){timeout=Nothing}})
setDepth :: Int -- ^ memoization depth. (Sub)expressions within this size are memoized, while greater expressions will be recomputed (to save the heap space).
-> IO ()
setDepth d = do PG (x,y,cmn) <- readIORef refmemodeb
writeIORef refmemodeb $ PG (x,y,cmn{opt = (opt cmn){memodepth=d}})
-- ^ Currently the default depth is 10. You may want to lower the value if your computer often swaps, or increase it if you have a lot of memory.
{-# NOINLINE refmemodeb #-}
refmemodeb :: IORef ProgGen
refmemodeb = unsafePerformIO (newIORef defaultMD)
defaultMD = mkPG [] :: ProgGen
trsToTCL :: [TypeRep] -> TyConLib -- ReadType.extractTyConLib :: [HsDecl] -> TyConLib¤ò»²¹Í¤Ë¤Ç¤¤ë¡¥ -- ¤³¤Î2¹Ô¤È
trsToTCL trs
= (Map.fromListWith (\new old -> old) [ tup | k <- [0..7], tup <- tcsByK ! k ], tcsByK)
where tnsByK :: Array Types.Kind [TypeName]
tnsByK = accumArray (flip (:)) [] (0,7) ( trsToTCstrs trs ) -- ¤³¤³¤òÊѤ¨¤¿¡¥
tcsByK :: Array Types.Kind [(TypeName,Types.TyCon)]
tcsByK = listArray (0,7) [ tnsToTCs (tnsByK ! k) | k <- [0..7] ]
tnsToTCs :: [TypeName] -> [(TypeName,Types.TyCon)]
tnsToTCs tns = zipWith (\ i tn -> (tn, i)) [0..] tns
-- x ¼ÂºÝ¤Ë¤Ï(->)¤ÏTyCon°·¤¤¤Ë¤Ï¤·¤Ê¤¤¤ó¤À¤±¤É¡¤¤Û¤ó¤Î¤Á¤ç¤Ã¤È¤À¤±ÌµÂ̤ˤʤë¤À¤±¤Ê¤Î¤Ç¤¤¤¤¤Ç¤·¤ç¡¥
trsToTCstrs :: [TypeRep] -> [(Int, String)] -- Int is the arity of the TyCon. There can be duplicates.
trsToTCstrs [] = []
trsToTCstrs (tr:ts) = case splitTyConApp tr of (tc,trs) -> (length trs, tyConString tc) : trsToTCstrs (trs++ts)
-- Memo¤ägetEverything¼«ÂΤÏIORef¤ò»È¤ï¤º¤ËIO¤Ê¤·¤Ç¼ÂÁõ¤Ç¤¤ëÌõ¤Ç¡¤¤½¤Î°ÕÌ£¤Ç¤Ï¡¤IORef¤ò»È¤ï¤Ê¤¤Êý¤¬¤¤¤¤¤«¤â¡¥
-- x ¤Ä¤¤¤Ç¤Ë¤¤¤¦¤È¡¤1ÉäǤΥ¿¥¤¥à¥¢¥¦¥È¤òɽ¤¹PTO¡Ê¤ÎGLOBAL_VAR¡Ë¤âIO¤Ê¤·¤ÇÍѰդǤ¤ë¡¥¡ÊunsafePerformIO»È¤¦¤±¤É¡Ë
-- | 'getEverything' uses the \'global\' values set with @set*@ functions. 'getEverythingF' is its filtered version
getEverything :: Typeable a => IO (Every a)
getEverything = do memodeb <- readIORef refmemodeb
return (everything memodeb)
getEverythingF :: Typeable a => IO (Every a)
getEverythingF =do memodeb <- readIORef refmemodeb
return (everythingF memodeb)
{-
getEverything = result
where ty = typeOf $ snd $ head $ head $ unsafePerformIO result
result = do memodeb@(trie,prims,depth,tcl) <- readIORef refmemodeb
return $ unMx $ toMx (fmap (\ e -> (exprToTHExp (error "unknown conlib") e, unsafeExecute e)) (matchingPrograms (trToType tcl ty) memodeb))
-}
-- | 'everything' generates all the expressions that fit the inferred type, and their representations in the 'TH.Exp' form.
-- It returns a stream of lists, which is equivalent to Spivey's @Matrix@ data type, i.e., that contains expressions consisted of n primitive components at the n-th element (n = 1,2,...).
-- 'everythingF' is its filtered version
everything, everythingF :: (ProgramGenerator pg, Typeable a) =>
pg -- ^ program generator
-> Every a
everything memodeb = et undefined memodeb (mxExprToEvery "MagicHaskeller.everything: type mismatch" memodeb)
everythingF memodeb = et undefined memodeb (mxExprFiltEvery "MagicHaskeller.everythingF: type mismatch" memodeb)
et :: (ProgramGenerator pg, Typeable a) =>
a -- ^ dummy argument
-> pg -- ^ program generator
-> (Types.Type -> Matrix AnnExpr -> Matrix (Exp, a))
-> Every a
et dmy memodeb filt = unMx $ filt ty $ matchingPrograms ty memodeb
where ty = trToType (extractTCL memodeb) (typeOf dmy)
noFilter :: ProgramGenerator pg => pg -> Types.Type -> a -> a
noFilter _m _t = id
mxExprToEvery :: (Expression e, Search m, ProgramGenerator pg, Typeable a) => String -> pg -> Types.Type -> m e -> m (Exp, a)
mxExprToEvery msg memodeb _ = fmap (unwrapAE msg memodeb . toAnnExpr (reducer memodeb))
mxExprFiltEvery :: (Expression e, FiltrableBF m, ProgramGenerator pg, Typeable a) => String -> pg -> Types.Type -> m e -> m (Exp, a)
mxExprFiltEvery msg memodeb ty = fmap (unwrapAE msg memodeb) . randomTestFilter memodeb ty . fmap (toAnnExpr (reducer memodeb))
unwrapAE :: (ProgramGenerator pg, Typeable a) => String -> pg -> AnnExpr -> (Exp, a)
unwrapAE msg memodeb (AE e dyn) = (exprToTHExp (extractVL memodeb) e, fromDyn tcl dyn (error msg))
where tcl = extractTCL memodeb
{-
̵¸Â¥ê¥¹¥È¤ò»È¤¦¤Ê¤é¡¤unsafeInterleaveIO¤¬É¬ÍפʤϤº¡¥¤½¤Î¾ì¹çIO¤ËÆÃ²½¤¹¤ë¤³¤È¤Ë¤Ê¤ë¡¥
-}
everythingM :: (ProgramGenerator pg, Typeable a, Monad m, Functor m) =>
pg -- ^ program generator
-> Int -- ^ query depth
-> m [(TH.Exp, a)]
everythingM = eM undefined
eM :: (ProgramGenerator pg, Typeable a, Monad m, Functor m) =>
a -- ^ dummy argument
-> pg -- ^ program generator
-> Int
-> m [(TH.Exp, a)]
eM dmy memodeb = result
where tcl = extractTCL memodeb
ty = trToType tcl $ typeOf dmy
result = unRcT $ mxExprToEvery "MagicHaskeller.everythingM: type mismatch" memodeb undefined $ matchingPrograms ty memodeb
everythingIO :: (ProgramGenerator pg, Typeable a) =>
pg -- ^ program generator
-> EveryIO a
everythingIO = eIO undefined
eIO :: (ProgramGenerator pg, Typeable a) =>
a -- ^ dummy argument
-> pg -- ^ program generator
-> EveryIO a
eIO dmy memodeb = result
where tcl = extractTCL memodeb
ty = trToType tcl $ typeOf dmy
result = unRcT $ mxExprToEvery "MagicHaskeller.everythingIO: type mismatch" memodeb undefined $ matchingProgramsIO ty memodeb
strip :: m (Every a) -> a
strip = undefined
stripEvery :: Every a -> a
stripEvery = head . map snd . concat
unifyable, matching, unifyableF, matchingF :: ProgramGenerator pg =>
pg -- ^ program generator
-> TH.Type -- ^ query type
-> [[TH.Exp]]
-- ^ Those functions are like 'everything', but take 'TH.Type' as an argument, which may be polymorphic.
-- For example, @'printQ' ([t| forall a. a->a->a |] >>= return . 'unifyable' True 10 memo)@ will print all the expressions using @memo@ whose types unify with @forall a. a->a->a@.
-- (At first I (Susumu) could not find usefulness in finding unifyable expressions, but seemingly Hoogle does something alike, and these functions might enhance it.)
unifyable memodeb tht = unMx $ genExps noFilter unifyingPrograms memodeb tht
matching memodeb tht = unMx $ genExps noFilter matchingPrograms memodeb tht
-- unifyablePos memodeb tht = unMx $ toMx $ fmap (\(es,subst,mx) -> (map (pprintUC . exprToTHExp (extractVL memodeb)) es, subst, mx)) $ unifyingPossibilities (thTypeToType (extractTCL memodeb) tht) memodeb
unifyableF memodeb tht = unMx $ genExps randomTestFilter unifyingPrograms memodeb tht
matchingF memodeb tht = unMx $ genExps randomTestFilter matchingPrograms memodeb tht
genExps filt rawGenProgs memodeb tht
= case thTypeToType (extractTCL memodeb) tht of
ty -> fmap (exprToTHExp (extractVL memodeb) . toCE) $
filt memodeb ty $ fmap (toAnnExpr (reducer memodeb)) (rawGenProgs ty memodeb)
-- Another advantage of these functions is that you do not need to define @instance Typeable@ for user defined types.
-- ¤È»×¤Ã¤¿¤±¤É¡¤GHC¤Ç¤Ïderiving Typeable¤Ç´Êñ¤ËÄêµÁ¤Ç¤¤ë¤·¡¤Typeable¤¬ÄêµÁ¤Ç¤¤Ê¤¤·¿¤Ê¤ó¤Æ¤Ê¤µ¤½¤¦¡Êderiving Typeable¤·Ëº¤ì¤¿data type¤ò´Þ¤àdata¤¬¤½¤¦¡©¡Ë
-- specializedPossi memodeb tht = unMx $ toMx $ fmap show (specializedPossibleTypes (thTypeToType (extractTCL memodeb) tht) memodeb)
{-
wrappit :: (Search m, Functor m, Typeable a) => m CoreExpr -> [[(TH.Exp,a)]]
wrappit = unMx . toMx . fmap (\ e -> (exprToTHExp e, unsafeExecute e))
-}
-- | @'findOne' pred@ finds an expression 'e' that satisfies @pred e == True@, and returns it in 'TH.Exp'.
findOne :: Typeable a => (a->Bool) -> TH.Exp
findOne pred = unsafePerformIO $ findDo (\e _ -> return e) pred
{- x ǰ¤Î¤¿¤á¤ä¤Ã¤Æ¤ß¤¿¤±¤É¡¤¤ä¤Ã¤Ñ¥À¥á¤ä¤Í¡¥¤Æ¤æ¡¼¤«¡¤Recomp¤Î¤Þ¤Þ¤ä¤Ã¤Æ³Æ¿¼¤µ¤Ç¸«¤ë¼ê¤Ï¤¢¤ë¤«¤â¡¥
findAny :: Typeable a => (a->Bool) -> [TH.Exp]
findAny pred = unsafePerformIO $ findDo (\e r -> r >>= \es -> return (e:es)) pred
-}
-- | 'printOne' prints the expression found first.
printOne :: Typeable a => (a->Bool) -> IO TH.Exp
printOne pred = do expr <- findDo (\e _ -> return e) pred
putStrLn $ pprintUC expr
return expr
-- | 'printAll' prints all the expressions satisfying the given predicate.
printAll, printAny :: Typeable a => (a->Bool) -> IO ()
printAny = printAll -- provided just for backward compatibility
printAll = findDo (\e r -> putStrLn (pprintUC e) >> r)
printAllF :: (Typeable a, Filtrable a) => (a->Bool) -> IO ()
printAllF pred = do et <- getEverything
fet <- filterThenF pred et
pprs fet
findDo :: Typeable a => (TH.Exp -> IO b -> IO b) -> (a->Bool) -> IO b
findDo op pred = do et <- getEverything
md <- readIORef refmemodeb
let mpto = timeout $ opt $ extractCommon md
fp mpto (concat et)
where fp mpto ((e,a):ts) = do -- hPutStrLn stderr ("trying" ++ pprintUC e)
result <- maybeWithTO seq mpto (return (pred a))
case result of Just True -> e `op` fp mpto ts
Just False -> fp mpto ts
Nothing -> hPutStrLn stderr ("timeout on "++pprintUC e) >> fp mpto ts
-- x ËÜÅö¤Ïrecomp¤Î¤Þ¤Þ¤Ç¤ä¤Ã¤¿Êý¤¬Â®¤¤¤Ï¤º¡¥
-- | 'filterFirst' is like 'printAll', but by itself it does not print anything. Instead, it creates a stream of expressions represented in tuples of 'TH.Exp' and the expressions themselves.
filterFirst :: Typeable a => (a->Bool) -> IO (Every a)
filterFirst pred = do et <- getEverything
filterThen pred et
-- randomTestFilter should be applied after filterThen, because it's slower
filterFirstF :: (Typeable a, Filtrable a) => (a->Bool) -> IO (Every a)
filterFirstF pred = do et <- getEverything
filterThenF pred et
filterThenF pred et = do
fd <- filterThen pred et
memodeb <- readIORef refmemodeb
let mpto = timeout $ opt $ extractCommon memodeb
return $ everyF mpto fd
{- refmemodeb ¤Ë¤¢¤ë¤â¤Î¤¬¼ÂºÝ¤Ë»È¤ï¤ì¤Æ¤¤¤ë¤â¤Î¤È¤Ï¸Â¤é¤Ê¤¤¡¥refmemodeb¤ò»È¤ï¤Ê¤¤¤È¤¤¤¦ÁªÂò¤â¤¢¤ë¤Î¤Ç¡¥
filterFirstF pred = do et <- getEverything
filterThenF pred et
filterThenF pred ts = do
fd <- filterThen pred ts
let x=undefined
_=pred x
memodeb <- readIORef refmemodeb
return $ unMx $ randomTestFilter memodeb (getType memodeb x) $ Mx et
getType :: Typeable a => a -> ProgGen -> Types.Type
getType ty memodeb = trToType (extractTCL memodeb) (typeOf ty)
-}
everyF :: (Typeable a, Filtrable a) =>
Maybe Int -- ^ microsecs until timeout
-> Every a -> Every a
everyF mto = unMx . unsafeRandomTestFilter mto . Mx
-- | 'filterThen' may be used to further filter the results.
filterThen :: Typeable a => (a->Bool) -> Every a -> IO (Every a)
filterThen pred ts = do md <- readIORef refmemodeb
let mpto = timeout $ opt $ extractCommon md
return (map (fp mpto) ts)
where fp _ [] = []
fp mpto (ea@(e,a):ts) = case unsafePerformIO (maybeWithTO seq mpto (return (pred a))) of
Just True -> ea : fp mpto ts
_ -> fp mpto ts
-- | @io2pred@ converts a specification given as a set of I/O pairs to the predicate form which other functions accept.
io2pred :: Eq b => [(a,b)] -> ((a->b)->Bool)
io2pred ios f = all (\(a,b) -> f a == b) ios
-- utility functions to pretty print the results
-- | 'pprs' pretty prints the results to the console, using 'pprintUC'
pprs :: Every a -> IO ()
pprs = mapM_ (putStrLn . pprintUC . fst) . concat
-- | 'pprsIO' is the 'EveryIO' version of pprs
pprsIO :: EveryIO a -> IO ()
pprsIO eio = mapM_ (\d -> eio d >>= mapM_ (putStrLn . pprintUC . fst)) [0..]
-- | @pprsIOn depth eio@ is the counterpart of @pprs (take depth eio)@, while @pprsIO eio@ is the counterpart of @pprs eio@.
-- Example: @pprsIOn 5 (everythingIO (mlist::ProgGen) :: EveryIO ([Char]->[Char]))@
pprsIOn :: Int -> EveryIO a -> IO ()
pprsIOn depth eio = mapM_ (\d -> eio d >>= mapM_ (putStrLn . pprintUC . fst)) [0..depth-1]
-- | 'pprintUC' is like 'Language.Haskell.TH.pprint', but unqualifies (:) before pprinting in order to avoid printing "GHC.Types.:" which GHCi does not accept and sometimes annoys when doing some demo.
pprintUC :: (Ppr a, Data a) => a -> String
pprintUC = pprint . everywhere (mkT unqCons)
unqCons :: Name -> Name
unqCons n | show n == show '(:) = mkName ":" -- NB: n == '(:) would not work due to the definition of Eq Name.
| otherwise = n
lengths :: Every a -> IO ()
lengths = print . map length
lengthsIO :: EveryIO a -> IO ()
lengthsIO eio = mapM_ (\d -> eio d >>= putStr . (' ':) . show . length) [0..]
lengthsIOn :: Int -> EveryIO a -> IO ()
lengthsIOn depth eio = mapM_ (\d -> eio d >>= putStr . (' ':) . show . length) [0..depth-1]
printQ :: (Ppr a, Data a) => Q a -> IO ()
printQ q = runQ q >>= putStrLn . pprintUC
\end{code}