From d2043e17e331cbe715937ef78c54e88662e20e77 Mon Sep 17 00:00:00 2001 From: Gregory Hale Date: Fri, 30 Jun 2023 15:47:27 -0700 Subject: [PATCH] add some tests and cleanup --- src/Pact/Repl/Lib.hs | 12 +++++++++++- src/Pact/Types/Memoize.hs | 6 ++++++ tests/pact/memoize.repl | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/pact/memoize.repl diff --git a/src/Pact/Repl/Lib.hs b/src/Pact/Repl/Lib.hs index 24566c10b..c030361e5 100644 --- a/src/Pact/Repl/Lib.hs +++ b/src/Pact/Repl/Lib.hs @@ -288,6 +288,10 @@ replDefs = ("Repl", [] ("WIP") + ,defZRNative "env-clear-memotable" envClearMemotable + (funType tTyString []) + ["(env-clear-memotable)"] + "Reset the memoization table." ]) where json = mkTyVar "a" [tTyInteger,tTyString,tTyTime,tTyDecimal,tTyBool, @@ -916,4 +920,10 @@ envMemoize _i [TApp (App memoFun memoArgs _) _ ] = do let table1 = unguardedInsert (entry, result') table0 evalMemoTable .= table1 return $ deepseq table1 $ tStr "Ok" -envMemoize _i _ = error "Wrong args" +envMemoize i as = argsError' i as + +envClearMemotable :: RNativeFun LibState +envClearMemotable _i [] = do + evalMemoTable .= mempty + return $ tStr "Ok" +envClearMemotable i as = argsError i as diff --git a/src/Pact/Types/Memoize.hs b/src/Pact/Types/Memoize.hs index a5527eed4..bfe4ef2c6 100644 --- a/src/Pact/Types/Memoize.hs +++ b/src/Pact/Types/Memoize.hs @@ -65,6 +65,12 @@ data MemoTable = MemoTable { instance NFData MemoTable instance Default MemoTable where def = MemoTable mempty +instance Semigroup MemoTable where + MemoTable a <> MemoTable b = MemoTable (a <> b) + +instance Monoid MemoTable where + mempty = MemoTable mempty + -- Insert a pair of function application and result into the memotable. -- Insertion is guarded by a `Witness` - a means of asserting that -- the pair is valid. The `Witness` is evaluated in some monad, diff --git a/tests/pact/memoize.repl b/tests/pact/memoize.repl new file mode 100644 index 000000000..65eebd51f --- /dev/null +++ b/tests/pact/memoize.repl @@ -0,0 +1,32 @@ +(env-gasmodel "table") +(env-gaslimit 1000000) + +; Define an expensive function, which we will use to test memoization. +(module m g + (defcap g () true) + (defun go(n:integer) "Do an expensive computation" + (let ((xs (enumerate 1 n)) + (fn (lambda (a b) (+ a b)))) + (fold (fn) 0 xs) + ))) + +; We will test memoization by checking that gas usage is lower +; for a memo table hit than for a miss. +(env-gas 0) +(m.go 10) +(expect "Executing unmemoized function costs gas" 36 (env-gas)) + +(env-memoize (m.go 10)) +(env-gas 0) +(m.go 10) +(expect "Executing memoized function is cheap" 0 (env-gas)) + + +(env-gas 0) +(shift 10 (shift 1 1)) +(expect "Executing unmemoized native costs gas" 3 (env-gas)) + +(env-memoize (shift 10 (shift 1 1))) +(env-gas 0) +(shift 10 2) +(expect "Executing memoized native is cheap" 0 (env-gas))