Reputation: 2002
Imagine such a function:
bar :: Foo -> A -> B -> C -> IO ()
That function performs some IO
stuff using a Foo
and other values. The Foo
value has to be passed to bar
, and can be retrieved from IO
via this:
foo :: X -> IO Foo
Now, A
, B
, C
and X
are all plain pure values. I’d rather like such a bar
function:
bar :: X -> A -> B -> C -> IO ()
And Foo
would be generated in the bar
function using the X
value. If I do that :
let f = bar myX
f :: A -> B -> C -> IO ()
. If I call that function several times, the X
value remains the same because of partial application, but since it’s an IO
effect, it will be generated each time. Is there a native, built-in-ghc way to perform some kind of caching so that the Foo
value is generated once – for the generated closure? I guess it’s all boxing-related, but I never figured out how to do that without using dirty IORef
, expanding the parameters of bar
, which is ugly.
Upvotes: 5
Views: 470
Reputation: 18189
What you are literally asking would break referential transparency, a big "no" in Haskell. So that leaves me with the question, should I show you the unsafeLaunchMissiles
kind of method that does (sometimes, if you are lucky and optimizations don't break it) what you literally ask but is highly discouraged, or should I show the clean way that changes the types just a little? Let me try the latter.
If you make your bar
have the following type instead:
bar :: X -> IO (A -> B -> C -> IO ())
Then you can use, in a do
block:
f <- bar myX
Alternatively, if you think that misses the point of redefining bar
to take an X
, then instead keep your first type for bar
and do
f <- bar =<< foo myX
Upvotes: 12