In the paper “Making a Fast Curry: Push/Enter vs. Eval/Apply for Higher-order Languages” by Simon Marlow and Simon Peyton Jones it is told that a PAP heap object may be created in the push/enter model (Figure 2. “The evaluation rules.” “Rules for push/enter.”). It is created “if there aren’t enough pending arguments on the stack.” I can't figure out an example of a type correct program which execution may lead to such a situation.
Functions can be partially applied, so you can end up with a situation in which a function is called with "not enough" arguments. For example, consider the
(* map : ∀α,β. (α → β) → list α → list β *) let rec map f xs = match xs with |  ->  | x :: xs -> (f x) :: map f xs
This will take a function
f as an argument, and then pass it one argument, once for each element of the list. Now, consider a two argument function
(* val foo : int → int → int *) let foo x y = 2*x + y
Then, if you map
foo over a list of integers:
(* val bar : list (int → int → int) *) let bar = map foo [1; 2; 3]
You get a thunk (because this paper is about lazy evaluation). To force one of these thunks, you need to scrutinize the list to get its head, and then force the evaluation of the head by applying it:
let baz = match bar with | f :: fs -> f 6
Now, scrutinizing bar will get you
f bound to
THUNK (foo 1), and
fs bound to
map foo [2;3]. Then, to apply
f 6, we first evaluate
foo 1. This pushes 1 on the stack, and since
foo is really a two-argument function,
foo 1 will not evaluate further -- it will return a fresh
p, bound to
Now the result is the thunk
THUNK(p 6) -- to drive evaluation further, you have to demand this thunk.
Consider the following lazy functional program:
doArith :: Int -> Int doArith n = if n < 0 then 1 + 2 else 3 - 4
A compiler can figure out that it doesn't need to build a thunk for
1 + 2 or
3 - 4 in the
if expression. This is because that an
if expression is strict in the branch position, since either
1 + 2 or
3 - 4 will surely be evaluated after evaluating
n < 0. In this way, the compiler can generate better code while still preserving the lazy semantics.
However, the following program shows some problem:
getFunction :: Int -> Int -> Int getFunction n = if n < 0 then (+) 1 else (-) 2
Here, the compiler will still generate strict code that enters either
(-) with only one argument. But
(-) require two arguments... So here comes the PAp object.
For further reading, I would suggest Simon Peyton Jones's implementing functional languages: a tutorial. It illustrates, step by step, three ways to implement lazy functional programming language.