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 7412375
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 29, 20262026-05-29T06:31:48+00:00 2026-05-29T06:31:48+00:00

So the short version of my question is, how are we supposed to encode

  • 0

So the short version of my question is, how are we supposed to encode loops in Haskell, in general? There is no tail optimization guarantee in Haskell, bang patterns aren’t even a part of the standard (right?), and fold/unfold paradigm is not guaranteed to work in all situation. Here’s case in point were only bang-patterns did the trick for me of making it run in constant space (not even using $! helped … although the testing was done at Ideone.com which uses ghc-6.8.2).

It is basically about a nested loop, which in list-paradigm can be stated as

prod (sum,concat) . unzip $ 
    [ (c, [r | t]) | k<-[0..kmax], j<-[0..jmax], let (c,r,t)=...]
prod (f,g) x = (f.fst $ x, g.snd $ x)

Or in pseudocode:

let list_store = [] in
for k from 0 to kmax
    for j from 0 to jmax
        if test(k,j) 
            list_store += [entry(k,j)]
        count += local_count(k,j)
result = (count, list_store)

Until I added the bang-pattern to it, I got either a memory blow-out or even a stack overflow. But bang patterns are not part of the standard, right? So the question is, how is one to code the above, in standard Haskell, to run in constant space?

Here is the test code. The calculation is fake, but the problems are the same. EDIT: The foldr-formulated code is:

testR m n = foldr f (0,[]) 
               [ (c, [(i,j) | (i+j) == d ])
                 | i<- [0..m], j<-[0..n], 
                   let c = if (rem j 3) == 0 then 2 else 1 ]
  where d = m + n - 3
    f (!c1, [])     (!c, h) = (c1+c,h) 
    f (!c1, (x:_))  (!c, h) = (c1+c,x:h)

Trying to run print $ testR 1000 1000 produces stack overflow. Changing to foldl only succeeds if using bang-patterns in f, but it builds the list in reversed order. I’d like to build it lazily, and in the right order. Can it be done with any kind of fold, for the idiomatic solution?

EDIT: to sum up the answer I got from @ehird: there’s nothing to fear using bang pattern. Though not in standard Haskell itself it is easily encoded in it as f ... c ... = case (seq c False) of {True -> undefined; _ -> ...}. The lesson is, only pattern match forces a value, and seq does NOT force anything by itself, but rather arranges that when seq x y is forced – by a pattern match – x will be forced too, and y will be the answer. Contrary to what I could understand from the Online Report, $! does NOT force anything by itself, though it is called a “strict application operator”.

And the point from @stephentetley – strictness is very important in controlling the space behaviour. So it is perfectly OK to encode loops in Haskell with proper usage of strictness annotations with bang patterns, where needed, to write any kind of special folding (i.e. structure-consuming) function that is needed – like I ended up doing in the first place – and rely on GHC to optimize the code.

Thank you very much to all for your help.

  • 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-29T06:31:49+00:00Added an answer on May 29, 2026 at 6:31 am

    Bang patterns are simply sugar for seq — whenever you see let !x = y in z, that can be translated into let x = y in x `seq` z. seq is standard, so there’s no issue with translating programs that use bang patterns into a portable form.

    It is true that Haskell makes no guarantees about performance — the report does not even define an evaluation order (only that it must be non-strict), let alone the existence or behaviour of a runtime stack. However, while the report doesn’t specify a specific method of implementation, you can certainly optimise for one.

    For example, call-by-need (and thus sharing) is used by all Haskell implementations in practice, and is vital for optimising Haskell code for memory usage and speed. Indeed, the pure memoisation trick1 (as relies on sharing (without it, it’ll just slow things down).

    This basic structure lets us see, for example, that stack overflows are caused by building up too-large thunks. Since you haven’t posted your entire code, I can’t tell you how to rewrite it without bang patterns, but I suspect [ (c, [r | t]) | ... ] should become [ c `seq` r `seq` t `seq` (c, [r | t]) | ... ]. Of course, bang patterns are more convenient; that’s why they’re such a common extension! (On the other hand, you probably don’t need to force all of those; knowing what to force is entirely dependent on the specific structure of the code, and wildly adding bang patterns to everything usually just slows things down.)

    Indeed, “tail recursion” per se does not mean all that much in Haskell: if your accumulator parameters aren’t strict, you’ll overflow the stack when you later try to force them, and indeed, thanks to laziness, many non-tail-recursive programs don’t overflow the stack; printing repeat 1 won’t ever overflow the stack, even though the definition — repeat x = x : repeat x — clearly has recursion in a non-tail position. This is because (:) is lazy in its second argument; if you traverse the list, you’ll have constant space usage, as the repeat x thunks are forced, and the previous cons cells are thrown away by the garbage collector.

    On a more philosophical note, tail-recursive loops are generally considered suboptimal in Haskell. In general, rather than iteratively computing a result in steps, we prefer to generate a structure with all the step-equivalents at the leaves, and do a transformation (like a fold) on it to produce the final result. This is a much higher-level view of things, made efficient by laziness (the structure is built up and garbage-collected as it’s processed, rather than all at once).2

    This can take some getting used to at first, and it certainly doesn’t work in all cases — extremely complicated loop structures might be a pain to translate efficiently3 — but directly translating tail-recursive loops into Haskell can be painful precisely because it isn’t really all that idiomatic.

    As far as the paste you linked to goes, id $! x doesn’t work to force anything because it’s the same as x `seq` id x, which is the same as x `seq` x, which is the same as x. Basically, whenever x `seq` y is forced, x is forced, and the result is y. You can’t use seq to just force things at arbitrary points; you use it to cause the forcing of thunks to depend on other thunks.

    In this case, the problem is that you’re building up a large thunk in c, so you probably want to make auxk and auxj force it; a simple method would be to add a clause like auxj _ _ c _ | seq c False = undefined to the top of the definition. (The guard is always checked, forcing c to be evaluated, but always results in False, so the right-hand side is never evaluated.)

    Personally, I would suggest keeping the bang pattern you have in the final version, as it’s more readable, but f c _ | seq c False = undefined would work just as well too.

    1 See Elegant memoization with functional memo tries and the data-memocombinators library.

    2 Indeed, GHC can often even eliminate the intermediate structure entirely using fusion and deforestation, producing machine code similar to how the computation would be written in a low-level imperative language.

    3 Although if you have such loops, it’s quite possible that this style of programming will help you simplify them — laziness means that you can easily separate independent parts of a computation out into separate structures, then filter and combine them, without worrying that you’ll be duplicating work by making intermediate computations that will later be thrown away.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Short version question : Is there navigator.mozIsLocallyAvailable equivalent function that works on all browsers,
SHORT VERSION OF QUESTION: So basically my question is: How can I set the
The short version of the question - why can't I do this? I'm restricted
The short version of the question: I do: x = y . Then I
I have a short version of the question: I start a thread like that:
I am relatively new to programming with Qt and had a question. Short version:
Short version of question: see title Long version of question: I've used jquery's show()
Short version of the question: If you have a table with a large number
Short version of the question: Since I already have TortoiseHg, I right clicked on
To short version of this question is that I want to accomplish something along

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.