Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mstksg/memotag
Memoized function application tuples with convenient lens interface
https://github.com/mstksg/memotag
Last synced: about 2 months ago
JSON representation
Memoized function application tuples with convenient lens interface
- Host: GitHub
- URL: https://github.com/mstksg/memotag
- Owner: mstksg
- License: mit
- Created: 2015-07-07T22:36:55.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2015-07-08T05:54:33.000Z (over 9 years ago)
- Last Synced: 2024-10-18T04:22:11.507Z (2 months ago)
- Language: Haskell
- Size: 113 KB
- Stars: 1
- Watchers: 4
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
memotag
=======Extremely small library offering "memoized function application tuples" with
restricted access using the lens library for convenient manipulation. Doesn't
require the lens library to use --- feel free to use lens-family, etc.Sometimes you want to work with a value as well as the result of a function
applied to the value; however, the function is pretty expensive, so you'd like
to also keep the result around memoized without much overhead.A common example is sorting a list based on the results of a function, or any
time you will be comparing the results of a function application, but want to
keep the value itself as the main object.Make a `MemoTag`:
~~~haskell
ghci> let mt = mkMemoTag sqrt 10
~~~The `mtValue` lens is useful for "mapping" functions over the value, or for
extracting it:~~~haskell
ghci> view mtValue mt
10
ghci> let mt' = over mtValue (*2) mt
ghci> view mtValue mt'
20
ghci> let mt'' = set mtValue 30 mt
ghci> view mtValue mt''
30
~~~The neat thing about `over` and using `mtValue` is that it "auto-updates" the
memoized result for you; it applies the result as you map it. We can see this
using the `mtResult` getter:~~~haskell
ghci> view mtResult mt
3.162278 -- square root of 10
ghci> view mtResult mt'
4.472136 -- square root of 20
ghci> view mtResult mt''
5.477226 -- square root of 30
~~~The "result" field is auto-updated when you use `over` and `set`.
You can also map over the function with `mtFunc`, which will also
auto-update the memoizing field.Because `mtValue` is a Traversal, you can even have your "mapping
function" do arbitrary side effects in a monad, like `traverse`:~~~haskel
ghci> let x = mkMemoTag (^2) 3
ghci> x' <- forOf mtValue x $ \y -> do print y
readLn
3 -- stdout output
> 10 -- prompted input with readLn
ghci> view mtValue x'
10
ghci> view mtResult x'
100
ghci> view mtTuple x'
(10, 100)
~~~Here, we applied a monadic function to update `mtValue`.
Here is a simple example for sorting based on two different things, using the
`Ord` instance:~~~haskell
ghci> let xs = [1..10]
ghci> let xs' = map (mkMemoTag sin) xs
ghci> map (view mtValue) . sort $ xs'
[5,4,10,6,3,9,7,1,2,8]
ghci> let xs'' = map (over mtValue negate) xs'
ghci> map (view mtValue) . sort $ xs''
[-8,-2,-1,-7,-9,-3,-6,-10,-4,-5]
~~~One main power of the lensy interface is both the unified power of using
`over` (for "mapping"), `view` (for "getting"), etc., under one interface, and
also to be able to "compose" lenses and getters using `(.)`:~~~haskell
ghci> let mt = mkMemoTag (uncurry (+)) (1,3)
ghci> let mt' = over (mtValue . _2) (*4) mt
ghci> view mtValue mt'
(1, 12)
ghci> view mtResult mt'
13
~~~If you don't want to use `view`/`over`, and don't want to compose lenses and
getters with `(.)`, there's also direct extractors (`_mtValue`, `_mtResult`)
and the `Comonad` and `ComonadStore` interfaces:~~~haskell
extract = view mtResult
pos = view mtValue
seek v = set mtValue v
seeks v = over mtValue f
peek v = view mtResult . set mtValue v
peeks f = view mtResult . over mtValue f
~~~So the above example could have been `seeks (*2)` instead of `over mtValue
(*2)`.All of the `ComonadStore` interface functions also auto-update the memoizing
field.