Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I ensure efficiency when using partial application in pure Haskell?

Tags:

haskell

I have some code that has structure equivalent to this:

import Debug.Trace

newtype SomeExpensiveHiddenType = SCHT Double

expensive :: Double -> Double -> SomeExpensiveHiddenType
expensive a b = SCHT $ trace "call expensive" (*) a b

cheap :: SomeExpensiveHiddenType -> Double -> Double
cheap (SCHT x) c = trace "call cheap" (+) x c

f1 :: Double -> Double -> Double -> Double
f1 a b c = let x = expensive a b in cheap x c

i.e. f1 is a function that computes an expensive result based upon the first two arguments, and then uses this with the third argument. I had hoped that a partial application on the the first 2 arguments, then repeated application of the 3rd argument would result in the expensive computation only being run once. Unfortunately this is not the case:

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

results in:

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

I've come up with what seems to be a solution:

newtype X a = X { unX :: a }
f2 :: Double -> Double -> X (Double -> Double)
f2 a b = let x = expensive a b 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)

resulting in:

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

But this seems quite messy. Is there a cleaner way I can avoid the redundant calls to the expensive calc?

like image 662
timbod Avatar asked Sep 05 '12 13:09

timbod


People also ask

How do you partially apply a function in Haskell?

If you call a multi-parameter function with less than its total number of parameters, then you are partially applying the function. Here we call sum , our previously defined two-parameter function, with only one argument and receive a new function.

What is a partial function Haskell?

From HaskellWiki. A partial function is a function that is not defined for all possible arguments of the specified type. Examples in the Haskell standard library are: head , tail : undefined for empty lists. (!!) : undefined if the index is at least as big as the list length.

What is partial application in JS?

Application in JavaScript means that a function is applied to its argument and produces a return value. So partial application also has to do with applying functions to some of their arguments. The function that is applied partially is returned to be used later.


1 Answers

You can just put the third argument inside the let, so that x is shared.

f2 a b = let x = expensive a b in \c -> cheap x c

(In this case f2 a b = let x = expensive a b in cheap x works too.)


What you are looking for is compiler-driven partial evaluation, and that is a hard problem... at least it is sufficiently hard to implement properly that it isn't in GHC.

like image 136
huon Avatar answered Nov 12 '22 04:11

huon