packages feed

memo-map (empty) → 0.0.0.0

raw patch · 7 files changed

+402/−0 lines, 7 filesdep +basedep +containersdep +markdown-unlit

Dependencies added: base, containers, markdown-unlit, memo-map, unliftio

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+## [_Unreleased_](https://github.com/freckle/memo-map/compare/v__...main)++## [v0.0.0.0](https://github.com/freckle/memo-map/tree/v0.0.0.0)++First tagged release.
+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2025 Freckle++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.lhs view
@@ -0,0 +1,79 @@+# memo-map++Utility for memoizing an effectful function (e.g. database query) using a map.++## Example++<!--+```haskell+module Main (main) where++import Prelude+import Text.Markdown.Unlit ()+```+-->++```haskell+import MemoMap+```++For demonstration, a silly little function that performs an effect and returns a value:++```haskell+f :: Int -> IO Int+f x = do+  putStrLn ("f " <> show x)+  pure (x * 10)+```++If `f` may be applied to the same argument repeatedly, perhaps it would be advantageous+to save the results from a previous application rather than repeating the action.++<!--+```haskell+main :: IO ()+main = do+```+-->++### Create a MemoMap++Turn `f` into a `MemoMap`.++```haskell+  mm <- newMemoMap f+```++### Use the memoized function++Use `runMemoMap mm` instead of `f` to run a _memoized_ version of `f`.++```haskell+  print =<< runMemoMap mm 2+  print =<< runMemoMap mm 2+  print =<< runMemoMap mm 3+```++Output:++    f 2+    20+    20+    f 3+    30++### Inspect the cache++You can also use `getMemoMap` to inspect the stored values.++```haskell+  print =<< getMemoMap mm+```++Output:++    fromList [(2,20),(3,30)]++---++[CHANGELOG](./CHANGELOG.md) | [LICENSE](./LICENSE)
+ README.md view
@@ -0,0 +1,79 @@+# memo-map++Utility for memoizing an effectful function (e.g. database query) using a map.++## Example++<!--+```haskell+module Main (main) where++import Prelude+import Text.Markdown.Unlit ()+```+-->++```haskell+import MemoMap+```++For demonstration, a silly little function that performs an effect and returns a value:++```haskell+f :: Int -> IO Int+f x = do+  putStrLn ("f " <> show x)+  pure (x * 10)+```++If `f` may be applied to the same argument repeatedly, perhaps it would be advantageous+to save the results from a previous application rather than repeating the action.++<!--+```haskell+main :: IO ()+main = do+```+-->++### Create a MemoMap++Turn `f` into a `MemoMap`.++```haskell+  mm <- newMemoMap f+```++### Use the memoized function++Use `runMemoMap mm` instead of `f` to run a _memoized_ version of `f`.++```haskell+  print =<< runMemoMap mm 2+  print =<< runMemoMap mm 2+  print =<< runMemoMap mm 3+```++Output:++    f 2+    20+    20+    f 3+    30++### Inspect the cache++You can also use `getMemoMap` to inspect the stored values.++```haskell+  print =<< getMemoMap mm+```++Output:++    fromList [(2,20),(3,30)]++---++[CHANGELOG](./CHANGELOG.md) | [LICENSE](./LICENSE)
+ memo-map.cabal view
@@ -0,0 +1,80 @@+cabal-version:      1.18+name:               memo-map+version:            0.0.0.0+license:            MIT+license-file:       LICENSE+maintainer:         Freckle Education+homepage:           https://github.com/freckle/memo-map#readme+bug-reports:        https://github.com/freckle/memo-map/issues+synopsis:           Memoization in a Map+description:+    Utility for memoizing an effectful function (e.g. database query) using a Map.++category:           Memoization+build-type:         Simple+extra-source-files: package.yaml+extra-doc-files:+    README.md+    CHANGELOG.md++source-repository head+    type:     git+    location: https://github.com/freckle/memo-map++library+    exposed-modules:    MemoMap+    hs-source-dirs:     src+    other-modules:      Paths_memo_map+    default-language:   GHC2021+    default-extensions:+        BangPatterns DataKinds DerivingStrategies GADTs+        GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses+        NoFieldSelectors NoImplicitPrelude NoMonomorphismRestriction+        OverloadedRecordDot OverloadedStrings StandaloneDeriving+        TypeApplications TypeFamilies++    ghc-options:+        -fwrite-ide-info -Weverything -Wno-all-missed-specialisations+        -Wno-missed-specialisations -Wno-missing-exported-signatures+        -Wno-missing-import-lists -Wno-missing-local-signatures+        -Wno-monomorphism-restriction -Wno-safe -Wno-unsafe+        -Wno-missing-kind-signatures -Wno-missing-safe-haskell-mode+        -Wno-prepositive-qualified-module++    build-depends:+        base >=4.16.4.0 && <5,+        containers >=0.6.5.1,+        unliftio >=0.2.25.0++    if impl(ghc >=9.8)+        ghc-options:+            -Wno-missing-role-annotations -Wno-missing-poly-kind-signatures++test-suite readme+    type:               exitcode-stdio-1.0+    main-is:            README.lhs+    other-modules:      Paths_memo_map+    default-language:   GHC2021+    default-extensions:+        BangPatterns DataKinds DerivingStrategies GADTs+        GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses+        NoFieldSelectors NoImplicitPrelude NoMonomorphismRestriction+        OverloadedRecordDot OverloadedStrings StandaloneDeriving+        TypeApplications TypeFamilies++    ghc-options:+        -fwrite-ide-info -Weverything -Wno-all-missed-specialisations+        -Wno-missed-specialisations -Wno-missing-exported-signatures+        -Wno-missing-import-lists -Wno-missing-local-signatures+        -Wno-monomorphism-restriction -Wno-safe -Wno-unsafe+        -Wno-missing-kind-signatures -Wno-missing-safe-haskell-mode+        -Wno-prepositive-qualified-module -pgmL markdown-unlit++    build-depends:+        base >=4.16.4.0 && <5,+        markdown-unlit >=0.5.1,+        memo-map++    if impl(ghc >=9.8)+        ghc-options:+            -Wno-missing-role-annotations -Wno-missing-poly-kind-signatures
+ package.yaml view
@@ -0,0 +1,72 @@+name: memo-map+version: 0.0.0.0+maintainer: Freckle Education+category: Memoization+github: freckle/memo-map+synopsis: Memoization in a Map+description: |+  Utility for memoizing an effectful function (e.g. database query) using a Map.++extra-doc-files:+  - README.md+  - CHANGELOG.md++extra-source-files:+  - package.yaml++ghc-options:+  - -fwrite-ide-info+  - -Weverything+  - -Wno-all-missed-specialisations+  - -Wno-missed-specialisations+  - -Wno-missing-exported-signatures # re-enables missing-signatures+  - -Wno-missing-import-lists+  - -Wno-missing-local-signatures+  - -Wno-monomorphism-restriction+  - -Wno-safe+  - -Wno-unsafe+  - -Wno-missing-kind-signatures+  - -Wno-missing-safe-haskell-mode+  - -Wno-prepositive-qualified-module++when:+  - condition: "impl(ghc >= 9.8)"+    ghc-options:+      - -Wno-missing-role-annotations+      - -Wno-missing-poly-kind-signatures++dependencies:+  - base < 5++language: GHC2021++default-extensions:+  - BangPatterns+  - DataKinds+  - DerivingStrategies+  - GADTs+  - GeneralizedNewtypeDeriving+  - LambdaCase+  - MultiParamTypeClasses+  - NoFieldSelectors+  - NoImplicitPrelude+  - NoMonomorphismRestriction+  - OverloadedRecordDot+  - OverloadedStrings+  - StandaloneDeriving+  - TypeApplications+  - TypeFamilies++library:+  source-dirs: src+  dependencies:+    - containers+    - unliftio++tests:+  readme:+    main: README.lhs+    ghc-options: -pgmL markdown-unlit+    dependencies:+      - memo-map+      - markdown-unlit
+ src/MemoMap.hs view
@@ -0,0 +1,66 @@+module MemoMap+  ( -- * MemoMap type+    MemoMap (..)+  , newMemoMap+  , runMemoMap+  , getMemoMap++    -- * Simplified usage+  , memoize+  ) where++import Prelude++import Data.Map (Map)+import Data.Map.Strict qualified as Map+import UnliftIO++newMapCache :: forall a b m. MonadIO m => m (IORef (Map a b))+newMapCache = newIORef Map.empty++-- | Create with 'newMemoMap', use with 'runMemoMap'+data MemoMap m a b = MemoMap+  { cacheRef :: IORef (Map a b)+  -- ^ Mutable reference to memoized results+  , uncachedFunction :: a -> m b+  -- ^ Original unmemoized action+  }++newMemoMap+  :: forall a b m1 m2+   . MonadIO m1+  => (a -> m2 b)+  -> m1 (MemoMap m2 a b)+newMemoMap uncachedFunction = do+  cacheRef <- newMapCache+  pure MemoMap {cacheRef, uncachedFunction}++runMemoMap+  :: forall a b m+   . (MonadUnliftIO m, Ord a)+  => MemoMap m a b+  -> a+  -> m b+runMemoMap MemoMap {cacheRef, uncachedFunction} a =+  withRunInIO $ \runInIO -> do+    m <- readIORef cacheRef+    case Map.lookup a m of+      Nothing -> do+        b <- runInIO $ uncachedFunction a+        writeIORef cacheRef $ Map.insert a b m+        pure b+      Just b ->+        pure b++getMemoMap :: MonadIO m => MemoMap m a b -> m (Map a b)+getMemoMap = liftIO . readIORef . (.cacheRef)++-- | Create a memoized variant of an effectful function (using 'MemoMap' internally)+memoize+  :: forall a b m1 m2+   . (MonadIO m1, MonadUnliftIO m2, Ord a)+  => (a -> m2 b)+  -> m1 (a -> m2 b)+memoize uncachedFunction = do+  cacheRef <- newMapCache+  pure $ runMemoMap MemoMap {cacheRef, uncachedFunction}