I have a data constructor with a few value constructors:
data DataType = C1 | C2 | C3 | ... | Cn
I’d like to build a function at run time from that data type to some other values (in fact, I’m doing this in an IO monad):
buildFun :: IO (DataType -> b)
buildFun = do
....
return $ \x -> case x of
C1 -> someProcessesToGetTheValue C1
...
Cn -> someProcessesToGetTheValue Cn
Will this mean that someProcessesToGetTheValue will be called each time I call the returned function?
I’d prefer Haskell to evaluate someProcessesToGetTheValue inside buildFun (since those calls are quite expensive) and return a function which returns these fully evaluated expressions.
Can I force that behaviour? Perhaps by doing something like the following?:
buildFun :: IO (DataType -> b)
buildFun = do
C1value <- return $ someProcessesToGetTheValue C1
...
Cnvalue <- return $ someProcessesToGetTheValue Cn
return $ \x -> case x of
C1 -> C1value
...
Cn -> Cnvalue
You don’t have to involve the IO monad at all (and indeed
do { x <- return v; ... }is identical tolet x = v in ...), just bind the values outside the lambda:Haskell doesn’t really specify anything about runtime evaluation behaviour, but on all common implementations this will ensure that the results are shared; see What does "floated out" mean? for more information.
However, it still won’t evaluate v1…vn inside
buildFun; instead, they will each be evaluated the first time the corresponding result of the function you return is evaluated. If you want to force them to be evaluated up-front, you can saylet !v1 = someProcessesToGetTheValue C1(this requires theBangPatternslanguage extension), orv1 <- evaluate $ someProcessesToGetTheValue C1(fromControl.Exception; this behaves better ifsomeProcessesToGetTheValue C1might throw an exception).