How to ensure efficiency when using a partial application in pure Haskell?

I have code that has a structure equivalent to this:

import Debug.Trace newtype SomeExpensiveHiddenType = SCHT Double expensive :: Double -> Double -> SomeExpensiveHiddenType expensive ab = SCHT $ trace "call expensive" (*) ab cheap :: SomeExpensiveHiddenType -> Double -> Double cheap (SCHT x) c = trace "call cheap" (+) xc f1 :: Double -> Double -> Double -> Double f1 abc = let x = expensive ab in cheap xc 

i.e. f1 is a function that calculates an expensive result based on the first two arguments, and then uses this with the third argument. I was hoping that a partial application of the first two arguments, and then reapplying the third argument, would result in the costly calculation being done only once. Unfortunately, this is not so:

 test1 = do putStrLn "test 1" let p = f1 2 3 print (p 0.1) print (p 0.2) print (p 0.3) 

leads to:

 *Main> test1 test 1 call cheap call expensive 6.1 call cheap call expensive 6.2 call cheap call expensive 6.3 *Main> 

I came up with what seems like a solution:

 newtype X a = X { unX :: a } f2 :: Double -> Double -> X (Double -> Double) f2 ab = let x = expensive ab in X (cheap x) test2 = do putStrLn "test 2" let p = unX $ f2 2 3 print (p 0.1) print (p 0.2) print (p 0.3) 

as a result of:

 *Main> test2 test 2 call cheap call expensive 6.1 call cheap 6.2 call cheap 6.3 *Main> 

But it seems pretty dirty. Is there a cleaner way to avoid redundant calls of expensive calc?

+7
source share
1 answer

You can simply put the third argument inside let so that x shared.

 f2 ab = let x = expensive ab in \c -> cheap xc 

(In this case, f2 ab = let x = expensive ab in cheap x works.)


What you are looking for is a partial evaluation compiler, and this is a difficult problem ... at least it is quite difficult to correctly execute that it is not in GHC.

+9
source

All Articles