| {-# INLINE foo #-}
| foo = large
|| bar x = if x then res else res
| where res = foo
|| By putting an INLINE on foo I am able to persuade it to be inlined
| into the binding of bar, but I can't then persuade it to be inlined at
| the let expression.
I'm not certain what you mean here. I think you mean that in the above code you end up with
bar x = let res = large in if x then res else res
whereas what you wanted was
bar x = if x then large else large
That is indeed tricky in general, as I'm sure you can see:
let x = <large> in
let y = e2[x,x] in
let z = e3[y] in
...
Is it better to inline x into e2, or y into e3, or z into e4? Hard to tell!
In your example, you want 'res' to inline "first". You can get that by explicit control:
{-# NOINLINE [0] foo #-}
That says "don't inline foo before phase 0", which in turn gives time for 'res' to get inlined first. I'm not certain whether that'll help in your actual example.
Simon