How to force bindings in the where clause to be CAF?

I have some bindings that I want to keep private for the function (therefore, not declared in the top-level module namespace), but which are expensive to calculate, so I would prefer them to be CAF. Is there a pragma or some other trick I could use to get the GHC to allocate CAF for these bindings?

code example:

header :: HeaderProps -> Element header = div_ [style_ headerStyle] [str_ "Here be headerz"] where -- Creating the 'headerStyle' is expensive! Do it only once -- regardless of how many times the 'header' function is used. headerStyle = mkStyle $ do display flex flexDirection column padding (px 20) (px 40) 

If this is not possible, I see several options, but each has its own drawbacks:

  • Move each function to its own module so that I can move expensive bindings to the top-level module namespace without worrying about other functions that access them. Since I expect that there will be many such functions, the number of modules will explode (hundreds in a large project). And I'm not a fan of the only function on the modular religion, as it is preached in the node.js. community
  • Move the bindings to the top-level module namespace and give each one a unique name to avoid conflicts, and make it clear that they are private (e.g. headerStyle → header__headerStyle ).
  • Use TemplateHaskell to offload expensive calculations at compile time.
+5
source share
1 answer

If I understood your intention correctly, this is actually easy: just move any function arguments to lambda, so the whole function (including the where block) is CAF:

 foo :: Int -> Int foo = \x -> x * nFermat where nFermat = length [() | a<-[1..m], b<-[1..m], c<-[1..m], a^3+b^3==c^3] m = 200 main = interact $ show . foos . read where foos n = foo <$> [0..n] 

Thus, regardless of the arguments x to be used, the same nFermat will be reused.

 sagemuej@sagemuej-X302LA :/tmp$ time runhaskell fermata.hs <<< 1 [0,0] real 0m23.199s user 0m23.177s sys 0m0.045s sagemuej@sagemuej-X302LA :/tmp$ time runhaskell fermata.hs <<< 100 [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] real 0m22.629s user 0m22.601s sys 0m0.052s 
+4
source

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


All Articles