Apesar do nome pomposo, função de alta ordem é um conceito bastante simples.
Existem dois tipos de função de alta ordem:

  1. Aquelas que recebem uma ou mais funções como argumentos
  2. Aquelas que devolvem outra função como valor de retorno

Hoje quero falar sobre o primeiro tipo.
Muitas funções de alta ordem do primeiro tipo são universais. Comumente teremos estas funções a nossa disposição ao lidarmos com uma API que propõe uma fundação para a programação funcional.

Vejamos por exemplo as funções map, fold, filter e find.
Estas funções são uma fundação comum para a resolução de problemas recorrentes ao lidarmos com coleções:

  • Transformar os elementos de uma coleção? map
  • Agregar dados dos elementos existentes? fold
  • Filtrar elementos que satisfaçam uma condição? filter
  • Encontrar um único elemento? find

Segue trecho de código do Scala Poker (um projeto meu) ilustrando o uso destas funções.

  def groupOf(size: Int)(cards: Seq[Card]): Option[Seq[Card]] =
    cards.groupBy(_.rank).map(_._2).find(size == _.size)

  def groupsOfTwo(cards: Seq[Card]): List[Seq[Card]] =
    cards.groupBy(_.rank).map(_._2).filter(2 == _.size)
      .toList.sortBy(_.head.rank)

Primeiro preciso facilitar o entendimento deste código para quem não conhece Scala:
_ (underline) quando precedido por ( é um açúcar sintático que indica o argumento recebido pela função. É mais prático do que definir explicitamente quem é o parâmetro esperado por uma função anônima.
_2 é o valor do segundo item de uma tupla. No caso nossa tupla contém: 1 -> peso e 2 -> todas as cartas que correspondem àquele peso.

Vamos então às funções de alta ordem:
A função groupOf procura por um conjunto de cartas de mesmo peso onde o tamanho deste conjunto deve satisfazer o argumento size. Para isto recorre às seguintes funções de alta ordem: groupBy (agrupando as cartas em tuplas (peso e conjuntos de cartas daquele peso), map (para transformar as tuplas em conjuntos de cartas (segundo item de cada tupla) e find (para encontrar entre estes conjuntos aquele que satisfaz o valor de size). Esta função pode retornar None (ausência de resultado) ou Some (resultado contendo o conjunto em questão). Em Scala este retorno é um valor do tipo Option[Seq[Card]].

A função groupsOfTwo segue uma idéia parecida. Desta vez recorrendo ao filter no lugar do find, isto porque filter serve para procurar por mais de um elemento enquanto find foi procurar por um único elemento. Esta função retorna um conjunto de resultados que pode ser vazio.

Funções de alta ordem tornam a base de código declarativa. Quando leio um código escrito por outro desenvolvedor estas funções me apontam o caminho tomado na resolução de um problema. Eu argumentaria que tal código é mais conciso e fácil de entender do que um código imperativo que recorra a instruções de laço (for/while/etc) e estruturas condicionais (if/else).

Estas funções costumam ser um ótimo ponto de partida para quem está começando com programação funcional.
Se você trabalha com .NET estas funções existem no universo do LINQ.
Se você trabalha com a linguagem Java considere estudar Scala, uma linguagem dez mil vezes mais moderna.
Se você precisa trabalhar com a linguagem Java (se aplica a mim hoje) dê uma olhada no projeto Guava. Aproveita e dá uma olhada também no projeto Lombok, que não tem nada a ver com o assunto mas é outro baita consolo para quem precisa codar em Java.

Rafa Noronha

Rafa Noronha gosta de construir aplicações web inovadoras em qualquer plataforma. Possui experiência em diversas tecnologias mas a única com quem rolou algo mais sério foi a Web. Nos últimos anos precisou se especializar em JavaScript, single-page apps e Backbone.js. Na Lambda3 Rafa Noronha jura que Java é legal e está sempre vencendo seus colegas nos confrontos de Mortal Kombat e FIFA14.