Na verdade, o código OO é muito menos reutilizável, e isso é por design. A idéia por trás do OOP é restringir as operações em partes específicas de dados a determinado código privilegiado que está na classe ou no local apropriado na hierarquia de herança. Isso limita os efeitos adversos da mutabilidade. Se uma estrutura de dados mudar, há apenas muitos lugares no código que podem ser responsáveis.
Com a imutabilidade, você não se importa com quem pode operar em qualquer estrutura de dados, porque ninguém pode alterar sua cópia dos dados. Isso facilita muito a criação de novas funções para trabalhar nas estruturas de dados existentes. Você acabou de criar as funções e agrupá-las em módulos que parecem apropriados do ponto de vista do domínio. Você não precisa se preocupar sobre onde encaixá-los na hierarquia de herança.
O outro tipo de reutilização de código é a criação de novas estruturas de dados para trabalhar nas funções existentes. Isso é tratado em linguagens funcionais usando recursos como genéricos e classes de tipo. Por exemplo, a classe de tipo Ord de Haskell permite que você use a sortfunção em qualquer tipo com uma Ordinstância. É fácil criar instâncias se elas ainda não existirem.
Tome seu Animalexemplo e considere implementar um recurso de alimentação. A implementação direta do OOP é manter uma coleção de Animalobjetos e percorrer todos eles, chamando o feedmétodo em cada um deles.
No entanto, as coisas ficam complicadas quando você detalha os detalhes. Um Animalobjeto sabe naturalmente que tipo de alimento ele come e quanto precisa para se sentir satisfeito. Ele não naturalmente sabe onde o alimento é mantido e quanto está disponível, portanto, um FoodStoreobjeto acaba de se tornar uma dependência de cada Animal, seja como um campo do Animalobjeto, ou passado como um parâmetro do feedmétodo. Como alternativa, para manter a Animalclasse mais coesa, você pode ir feed(animal)para o FoodStoreobjeto ou criar uma abominação para uma classe chamada de AnimalFeederalgo ou algo assim.
No FP, não há inclinação para os campos de um Animalpermanecerem sempre agrupados, o que tem algumas implicações interessantes para a reutilização. Digamos que você tenha uma lista de Animalregistros, com campos como name, species, location, food type, food amount, etc. Você também tem uma lista deFoodStore registros com campos como location, food type, e food amount.
O primeiro passo na alimentação pode ser mapear cada uma dessas listas de registros para listas de (food amount, food type) pares, com números negativos para as quantidades dos animais. Você pode criar funções para fazer todo tipo de coisa com esses pares, como somar as quantidades de cada tipo de alimento. Essas funções não pertencem perfeitamente a um Animalou a um FoodStoremódulo, mas são altamente reutilizáveis por ambos.
Você acaba com várias funções que fazem coisas úteis, [(Num A, Eq B)]reutilizáveis e modulares, mas você tem problemas para descobrir onde colocá-las ou como chamá-las como um grupo. O efeito é que os módulos FP são mais difíceis de classificar, mas a classificação é muito menos importante.