I’m having trouble understanding why Version 1 of this code performs about 10% better when compiled than Version 2. All I do in Version 2 is tidy up the variables to prevent them from being shadowed and remove some redundant functions. Any ideas?
Version 1
transform :: (Ord a, Floating a) => a -> a -> a -> a -> a -> a -> a
transform x0 l1 l2 a b x = lin (tra x x0 l1 l2) a b
where tra x x0 l1 l2 = (1-sig x x0) * (yeo x l1) + (sig x x0) * (yeo x l2)
sig x x0 = 1 / (1 + exp (-50 * (x - x0)))
lin x a b = a * x + b
yeo x l | l /= 0 && x >= 0 = ((x+1)**l - 1) / l
| l == 0 && x >= 0 = log (x + 1)
| l /= 2 && x < 0 = -((-x + 1)**(2-l)-1)/(2-l)
| otherwise = -log (-x + 1)
Version 2
transform :: (Ord a, Floating a) => a -> a -> a -> a -> a -> a -> a
transform x0 l1 l2 a b x = a * tra + b
where tra = (1-sig) * (yeo l1) + (sig) * (yeo l2)
sig = 1 / (1 + exp (-50 * (x - x0)))
yeo l | l /= 0 && x >= 0 = ((x+1)**l - 1) / l
| l == 0 && x >= 0 = log (x + 1)
| l /= 2 && x < 0 = -((-x + 1)**(2-l)-1)/(2-l)
| otherwise = -log (-x + 1)