Is there a way to remember a value in Haskell?

I have the following function in Haskell:

memdb = -- load the contents of a database into memory as a Map 

And then I have the following line:

 map (\x -> memdb ! x) values 

I would like memdb to generate Map only once, and not on each iteration of map . I could do this using something like this:

 make_memdb = -- equivalent to memdb in previous example memdb <- make_memdb map (\x -> memdb ! x) values 

But that would mean that I would have to pass memdb to every function that uses it. Is there any way:

a. avoid recounting memdb every time it is called OR

b. save the value expressed in make_memdb as a constant, so can I avoid passing it for every function that uses it?

+6
source share
3 answers

Since your map comes from a database, this means that it cannot be permanent, because it can be different between runs of your application.

But that would mean that I need to pass memdb to every function that uses it.

Yes, but there are tools to make it worse than it sounds. In particular, it sounds like an ideal option for a monad reader !

Monad readers are usually used when you have some meaning, for example, a configuration that you want to load at the beginning of your program and then be able to access it through your program, without forcing it to explicitly transmit it all the time. Here is a brief example of how you use it:

 main = do memdb <- make_memdb -- Get the memdb from the database once and for all runReaderT foo memdb foo = do memdb <- ask -- Grab the memdb. Will not reload from the database liftIO $ putStrLn "Hello, world" -- IO actions have to be lifted -- [...] 

See also:

+13
source

It seems you want to get memdb via IO as a way to avoid passing more parameters, right? Then you ask if you can (A) define memdb , implying that it will be a top-level function, without the overhead of loading data from the database, or (B) if you can save the loaded data structure with a global scope.

Both of these can be done using IORef and unsafePerformIO to define a mutable top-level global variable. I DO NOT OFFER YOU THIS. This is inconvenient and annoying refactoring. However, I will show you, as in any case:

Assuming you have a function:

 make_memdb :: IO (Map KV) 

You can declare a top-level mutable variable:

 import Data.Map as M import Data.IORef mRef :: IORef (Map KV) mRef = unsafePerformIO $ newIORef M.empty {-# NOINLINE mRef #-} main = do m <- make_memdb writeIORef mRef m ... do stuff using mRef ... stuffUsingMRef ... = do memdb <- readIORef let vs = map (memdb !) values return vs 

Please note that your functions will live forever in IO . This is because you need IO to read the global mutable variable in which you placed memdb . If you don’t like it and don’t like the transmission options, then study the state monad! I am sure that in another answer we will discuss this, which is the right decision.

+1
source

Source: https://habr.com/ru/post/896006/


All Articles