The first step is to turn your set of top-level equations for foldl into a lambda expression that uses case analysis, for example:
val rec foldl = fn f => fn b => fn lst => case lst of [] => b | (h::t) => foldl f (f(h,b)) t
Now you can use the same logic as before. Taking the function fn (x, y) => x * y as an example, we can see that
val prod = foldl (fn (x, y) => x * y)
equivalently
val prod = (fn f => fn b => fn lst => case lst of [] => b | (h::t) => foldl f (f(h,b)) t) (fn (x, y) => x * y)
which beta-reduce for
val prod = fn b => fn lst => case lst of [] => b | (h::t) => foldl (fn (x, y) => x * y) ((fn (x, y) => x * y)(h,b)) t
which beta comes down to
val prod = fn b => fn lst => case lst of [] => b | (h::t) => foldl (fn (x, y) => x * y) (h * b) t
Now, since it is known from our first definition that prod equivalent to foldl (fn (x, y) => x * y) , we can substitute it into our own definition:
val rec prod = fn b => fn lst => case lst of [] => b | (h::t) => prod (h * b) t
Then we mentally transform this back into a function defined by equations, if we like:
fun prod b [] = b | prod b (h::t) = prod (h * b) t
What about what you expect, right?