Actually, OO code is far less reusable, and that's by design. The idea behind OOP is to restrict operations on particular pieces of data to certain privileged code that's either in the class or in the appropriate place in the inheritance hierarchy. This limits the adverse effects of mutability. If a data structure changes, there are only so many places in the code that can be responsible.
With immutability, you don't care who can operate on any given data structure, because no one can change your copy of the data. This makes creating new functions to work on existing data structures much easier. You just create the functions and group them into modules that seem appropriate from a domain point of view. You don't have to worry about where to fit them into the inheritance hierarchy.
The other kind of code reuse is creating new data structures to work on existing functions. This is handled in functional languages using features like generics and type classes. For example, Haskell's Ord type class allows you to use the
sort function on any type with an
Ord instance. Instances are easy to create if they don't already exist.
Animal example, and consider implementing a feeding feature. The straightforward OOP implementation is to maintain a collection of
Animal objects, and loop through all of them, calling the
feed method on each of them.
However, things get tricky when you get down to details. An
Animal object naturally knows what kind of food it eats, and how much it needs in order to feel full. It does not naturally know where the food is kept and how much is available, so a
FoodStore object has just become a dependency of every
Animal, either as a field of the
Animal object, or passed in as a parameter of the
feed method. Alternately, to keep the
Animal class more cohesive, you might move
feed(animal) to the
FoodStore object, or you might create an abomination of a class called an
AnimalFeeder or some such.
In FP, there is no inclination for the fields of an
Animal to always stay grouped together, which has some interesting implications for reusability. Say you have a list of
Animal records, with fields like
food amount, etc. You also have a list of
FoodStore records with fields like
food type, and
The first step in feeding might be to map each of those lists of records to lists of
(food amount, food type) pairs, with negative numbers for the animals' amounts. You can then create functions to do all sorts of things with these pairs, like sum the amounts of each type of food. These functions don't belong perfectly to either an
Animal or a
FoodStore module, but are highly reusable by both.
You end up with a bunch of functions that do useful stuff with
[(Num A, Eq B)] that are reusable and modular, but you have trouble figuring out where to put them or what to call them as a group. The effect is that FP modules are more difficult to classify, but the classification is much less important.