Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 5999505
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 23, 20262026-05-23T00:33:43+00:00 2026-05-23T00:33:43+00:00

Suppose someone makes a program to play chess, or solve sudoku. In this kind

  • 0

Suppose someone makes a program to play chess, or solve sudoku. In this kind of program it makes sense to have a tree structure representing game states.

This tree would be very large, “practically infinite”. Which isn’t by itself a problem as Haskell supports infinite data structures.

An familiar example of an infinite data structure:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

Nodes are only allocated when first used, so the list takes finite memory. One may also iterate over an infinite list if they don’t keep references to its head, allowing the garbage collector to collect its parts which are not needed anymore.

Back to the tree example – suppose one does some iteration over the tree, the tree nodes iterated over may not be freed if the root of the tree is still needed (for example in an iterative deepening search, the tree would be iterated over several times and so the root needs to be kept).

One possible solution for this problem that I thought of is using an “unmemo-monad”.

I’ll try to demonstrate what this monad is supposed to do using monadic lists:

import Control.Monad.ListT (ListT)  -- cabal install List
import Data.Copointed  -- cabal install pointed
import Data.List.Class
import Prelude hiding (enumFromTo)

nums :: ListT Unmemo Int  -- What is Unmemo?
nums = enumFromTo 0 1000000

main = print $ div (copoint (foldlL (+) 0 nums)) (copoint (lengthL nums))

Using nums :: [Int], the program would take a lot of memory as a reference to nums is needed by lengthL nums while it is being iterated over foldlL (+) 0 nums.

The purpose of Unmemo is to make the runtime not keep the nodes iterated over.

I attempted using ((->) ()) as Unmemo, but it yields the same results as nums :: [Int] does – the program uses a lot of memory, as evident by running it with +RTS -s.

Is there anyway to implement Unmemo that does what I want?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-23T00:33:43+00:00Added an answer on May 23, 2026 at 12:33 am

    Same trick as with a stream — don’t capture the remainder directly, but instead capture a value and a function which yields a remainder. You can add memoization on top of this as necessary.

    data UTree a = Leaf a | Branch a (a -> [UTree a]) 
    

    I’m not in the mood to figure it out precisely at the moment, but this structure arises, I’m sure, naturally as the cofree comonad over a fairly straightforward functor.

    Edit

    Found it: http://hackage.haskell.org/packages/archive/comonad-transformers/1.6.3/doc/html/Control-Comonad-Trans-Stream.html

    Or this is perhaps simpler to understand: http://hackage.haskell.org/packages/archive/streams/0.7.2/doc/html/Data-Stream-Branching.html

    In either case, the trick is that your f can be chosen to be something like data N s a = N (s -> (s,[a])) for an appropriate s (s being the type of your state parameter of the stream — the seed of your unfold, if you will). That might not be exactly correct, but something close should do…

    But of course for real work, you can scrap all this and just write the datatype directly as above.

    Edit 2

    The below code illustrates how this can prevent sharing. Note that even in the version without sharing, there are humps in the profile indicating that the sum and length calls aren’t running in constant space. I’d imagine that we’d need an explicit strict accumulation to knock those down.

    {-# LANGUAGE DeriveFunctor #-}
    import Data.Stream.Branching(Stream(..))
    import qualified Data.Stream.Branching as S
    import Control.Arrow
    import Control.Applicative
    import Data.List
    
    data UM s a = UM (s -> Maybe a) deriving Functor
    type UStream s a = Stream (UM s) a
    
    runUM s (UM f) = f s
    liftUM x = UM $ const (Just x)
    nullUM = UM $ const Nothing
    
    buildUStream :: Int -> Int -> Stream (UM ()) Int
    buildUStream start end = S.unfold (\x -> (x, go x)) start
        where go x
               | x < end = liftUM (x + 1)
               | otherwise = nullUM
    
    sumUS :: Stream (UM ()) Int -> Int
    sumUS x = S.head $ S.scanr (\x us -> maybe 0 id (runUM () us) + x) x
    
    lengthUS :: Stream (UM ()) Int -> Int
    lengthUS x = S.head $ S.scanr (\x us -> maybe 0 id (runUM () us) + 1) x
    
    sumUS' :: Stream (UM ()) Int -> Int
    sumUS' x = last $ usToList $ liftUM $ S.scanl (+) 0  x
    
    lengthUS' :: Stream (UM ()) Int -> Int
    lengthUS' x = last $ usToList $ liftUM $ S.scanl (\acc _ -> acc + 1) 0 x
    
    usToList x = unfoldr (\um -> (S.head &&& S.tail) <$> runUM () um) x
    
    maxNum = 1000000
    nums = buildUStream 0 maxNum
    
    numsL :: [Int]
    numsL = [0..maxNum]
    
    -- All these need to be run with increased stack to avoid an overflow.
    
    -- This generates an hp file with two humps (i.e. the list is not shared)
    main = print $ div (fromIntegral $ sumUS' nums) (fromIntegral $ lengthUS' nums)
    
    -- This generates an hp file as above, and uses somewhat less memory, at the cost of
    -- an increased number of GCs. -H helps a lot with that.
    -- main = print $ div (fromIntegral $ sumUS nums) (fromIntegral $ lengthUS nums)
    
    -- This generates an hp file with one hump (i.e. the list is shared)
    -- main = print $ div (fromIntegral $ sum $ numsL) (fromIntegral $ length $ numsL)
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Suppose I have a stringbuilder in C# that does this: StringBuilder sb = new
Hopefully someone can give me a pointer. I have an application that makes several
Suppose I have a macro defined as this: #define FOO(x,y) \ do { int
Suppose someone (other than me) writes the following code and compiles it into an
I suppose it depends on how it's implemented. I'd love it if someone would
Suppose your git history looks like this: 1 2 3 4 5 1–5 are
Suppose you have 2 different ASP.NET applications in IIS. Also, you have some ASCX
Suppose we have a table A: itemid mark 1 5 2 3 and table
Suppose I have the following CSS rule in my page: body { font-family: Calibri,
Suppose I have a class module clsMyClass with an object as a member variable.

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.