In the homotopy type theory book in section 5.6, "the general syntax of inductive definitions", an example of a valid constructor for an inductive definition is given:
$$ c : (A \to W) \to (B \to C \to W) \to D \to W \to W $$
However, I don't see from this constructor type why a function of type
$$ d : (A \to W) \to (A \to P) \to (B \to C \to W) \to (B \to C \to P) \to D \to W \to P \to P $$
is needed to give the recursion principle (when attempting to define a function $f : W \to P$ recursively) for the inductively defined type $W$ with generator $c$. Given the material in section 5.4, it seems to me like the function $d$ should actually have the form
$$ d : (A \to P) \to (B \to C \to P) \to D \to P \to P $$
since $(P,d)$ would then be an $F$-algebra, where in this case $$ F(X) = (A \to X) \to (B \to C \to X) \to D \to X $$ with the map defined on morphisms in the evident way, and assuming our inductively defined type $(W,c)$ is an initial $F$-algebra, we can define $f : W \to P$ as the unique $F$-algebra morphism from $(W,c)$ to $(P,d)$.
Why is the $d$ defined in the book different from what the categorical semantics would seem to suggest as the proper data required to define a function $f : W \to P$ recursively?
If you have pairs, these are equivalent. Just set $P$ to $W\times P$ in your version of $d$ and you'll see that at least the types are isomorphic. To use some older FP terminology, the distinction is between a paramorphism and a catamorphism. Now we might say between a recursor and a fold. $c$ corresponds to the following constructor for some data type (using Haskell syntax) which, for clarity, I'll assume is the only constructor:
A fold would then look like:
A recursor would look like:
So what's happening here is that we're passing the subterms both recursively processed, like in
foldWand unprocessed. Note thefparameter corresponds to the existence of the $d$ function in both your and the book's variant in each of the definitions respectively. It will probably be clearer for a less arbitrary data type.Note that
recNcorresponds to primitive recursion, but also note that we're just additionally passing the predecessor to thesfunction inrecN. We can obviously definefoldN/foldWin terms ofrecN/recW. The other way is also not too difficult.So if you have pairs you can just continue to use initial algebra semantics. Without pairs things are more complicated which is why primitive recursion is a recursor and not a fold which would be more natural from a categorical perspective. It should also be clear why, even with pairs, we usually want to have the recursor rather than the fold as the recursor is easier to use and requires far less computation for many common patterns (e.g. "pattern matching"). To calculate the predecessor of a natural using
foldNrequires time and space linear in the natural and is slightly non-obvious to write. UsingrecN, it's constant time and trivial to write.