diff --git a/README.md b/README.md index cd75e07..4ee7cee 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,6 @@ Note that `fibonacciSlow` has been modified to call the faster `fibonacci` funct The `memoize` function can be applied whenever there is a `Tabulate` instance for the function argument type. This library provides instances of the `Tabulate` type class for common types, such as `Maybe`, `Either` and `Tuple`. +## Related resources + +- Slides: [Elegant memoization](https://github.com/conal/talk-2014-elegant-memoization/blob/master/README.md) by Conal Elliott - @conal diff --git a/bower.json b/bower.json index 4c81a80..1628f49 100644 --- a/bower.json +++ b/bower.json @@ -15,19 +15,16 @@ }, "license": "MIT", "dependencies": { - "purescript-lazy": "^3.0.0", - "purescript-either": "^3.0.0", - "purescript-maybe": "^3.0.0", - "purescript-tuples": "^4.0.0", - "purescript-integers": "^3.0.0", - "purescript-lists": "^4.0.1", - "purescript-generics-rep": "^5.0.0", - "purescript-strings": "^3.0.0" + "purescript-lazy": "^4.0.0", + "purescript-either": "^4.0.0", + "purescript-maybe": "^4.0.0", + "purescript-tuples": "^5.0.0", + "purescript-integers": "^4.0.0", + "purescript-lists": "^5.0.0", + "purescript-generics-rep": "^6.0.0", + "purescript-strings": "^4.0.0" }, "devDependencies": { - "purescript-refs": "^3.0.0", - "purescript-console": "^3.0.0", - "purescript-assert": "^3.0.0", - "purescript-quickcheck": "^4.0.0" + "purescript-console": "^4.0.0" } } diff --git a/package.json b/package.json index e6343ef..17ba914 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,9 @@ "build": "pulp build && pulp test" }, "devDependencies": { - "pulp": "^11.0.0", + "pulp": "^12.3.0", "purescript-psa": "^0.5.0", - "purescript": "^0.11.1", + "purescript": "^0.12.0", "rimraf": "^2.5.4" } } diff --git a/src/Data/Function/Memoize.purs b/src/Data/Function/Memoize.purs index 106212b..5abb124 100644 --- a/src/Data/Function/Memoize.purs +++ b/src/Data/Function/Memoize.purs @@ -20,9 +20,10 @@ import Data.Generic.Rep (class Generic, Argument(..), Constructor(..), NoArgumen import Data.Int.Bits ((.&.), zshr) import Data.Lazy (Lazy, force, defer) import Data.List (List(..), fromFoldable, toUnfoldable) -import Data.Maybe (Maybe(..)) -import Data.String (fromCharArray, toCharArray) +import Data.Maybe (Maybe(..), fromJust) +import Data.String.CodeUnits (fromCharArray, toCharArray) import Data.Tuple (Tuple(..), curry, uncurry) +import Partial.Unsafe (unsafePartial) -- | The `Tabulate` class identifies those types which can be used as the domain of -- | a memoized function, i.e. those for which the results can be _tabulated_. @@ -45,7 +46,7 @@ instance tabulateBool :: Tabulate Boolean where instance tabulateChar :: Tabulate Char where tabulate f = f1 <<< toCharCode where - f1 = tabulate (f <<< fromCharCode) + f1 = tabulate (f <<< unsafePartial fromJust <<< fromCharCode) instance tabulateString :: Tabulate String where tabulate f = f1 <<< toCharArray diff --git a/test/Main.purs b/test/Main.purs index 9605448..6d29891 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -1,19 +1,12 @@ module Test.Main where import Prelude -import Data.Generic.Rep as G -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) -import Control.Monad.Eff.Exception (EXCEPTION) -import Control.Monad.Eff.Random (RANDOM) -import Control.Monad.Eff.Ref (REF, newRef, modifyRef, readRef) -import Control.Monad.Eff.Unsafe (unsafePerformEff) import Data.Function.Memoize (class Tabulate, memoize, memoize2, genericTabulate) +import Data.Generic.Rep as G import Data.List ((:), length, singleton) import Data.String (take, drop) -import Test.QuickCheck (quickCheck') -import Test.QuickCheck.Arbitrary (class Arbitrary, arbitrary) -import Test.Assert (ASSERT, assert') +import Effect (Effect) +import Effect.Console (logShow) data Diff a = Add a | Remove a @@ -30,13 +23,7 @@ derive instance genericInts :: G.Generic Ints _ instance tabulateInts :: Tabulate Ints where tabulate = genericTabulate - -newtype SmallInt = SmallInt Int - -instance arbSmallInt :: Arbitrary SmallInt where - arbitrary = SmallInt <<< (_ `mod` 1000) <$> arbitrary - -main :: forall eff. Eff (assert :: ASSERT, ref :: REF, console :: CONSOLE, random :: RANDOM, exception :: EXCEPTION | eff) Unit +main :: Effect Unit main = do let fibonacciFast = go 0 1 where @@ -76,11 +63,3 @@ main = do (Remove (take 1 s1) : diff (drop 1 s1) s2) logShow $ diff "Hello, PureScript" "ello, PureScript!" - called <- newRef 0 - let fn x = 2 * x - msin = memoize \n -> unsafePerformEff do - modifyRef called (_ + 1) - pure $ fn n - quickCheck' 10000 $ \(SmallInt x) -> fn x == msin x - ncalled <- readRef called - assert' "Memoized function called too many times" (ncalled < 2000)