En este primer articulo sobre programacion funcional vamos a ver la parte que se refiere al funtor

Hace algunos meses escribi 3 articulos en el blog de Paradigma Digital sobre Programacion Funcional:

Aunque estos articulos dan una introduccion a algunos conceptos de la programacion funcional hay otros que se quedan fuera y que son muy interesantes. Recientemente he hecho varios cursos sobre programacion funcional en Hablapps y he aprendido muchas cosas que se pueden aplicar a la programacion para crecer profesionalmente y mejorar nuestros desarrollos

Un poco de teoria

Comencemos con un poco de teoria, en concreto, teoria de categorias. Todos los conceptos que vamos a ver son conceptos matematicos y ya que la informatica esta basada en conceptos matematicos todos estos se pueden aplicar

Una categoria, dicho de una forma simple, es una forma de representar cosas y de ir entre una cosa a otra cosa. Para una definicion mas amplia siempre podemos echar un vistazo en la wikipedia

Con lo que tenemos que quedarnos es con que una categoria tiene los siguientes elementos:

  • Objetos
  • Morfismos
  • Una ley de composicion

Intentare explicarlo de una forma simple. Si tenemos una categoria con 3 objetos, A, B y C donde tenemos un morfismo de A a B llamado f y un morfismo de B a C llamado g podemos componer f y g para obtener un morfismo de A a C

Las categorias pueden ser de cualquier cosa, Strings, numeros, listas, gatos…

Funtor

Visto esto, llegamos a la primera cosa que nos interesa, los funtores. Basicamente un funtor asocia objetos entre categorias

Kind

En Java tenemos tipos de objetos: String, Integer, List, Map, … Algunos de estos tipos pueden tener un kind que es un tipo de un tipo. Por ejemplo, la clase List puede tener un kind String y se representa con List<String>

Podemos crear un funtor que convierta de un tipo a otro de esta manera

class ListFunctor {

  List<String> map(List<Integer> fa, Function<Integer, String> f) {
    return fa.stream()
        .map(f)
        .collect(Collectors.toList());
}

Podemos hacer esta clase mas generica de la siguiente manera

class ListFunctor<A, B> {

  List<B> map(List<A> fa, Function<A, B> f) {
    return fa.stream()
        .map(f)
        .collect(Collectors.toList());
  }
}

Ahora esta clase nos vale para cualquier List con cualquier kind. Pero y si queremos hacer lo mismo para cualquier tipo, ya sea List, ArrayList, Map, …?

Veamos como seria nuestra clase, o mejor dicho, nuestra interfaz

public interface Functor<T> {

  <A, B> T<B> map(T<A> fa, Function<A, B> f);
}

Lamentablemente esto en Java no se puede hacer. Por suerte hay una libreria que nos permite hacer esto que se llama hkt y nuestro codigo quedaria asi

public interface Functor<f> {

  <A, B> __<f, B> map(__<f, A> fa, Function<A, B> f);
}

El unico problema es que no podemos usar las clases originales de Java y tenemos que hacer un pequeño wrapper para poder utilizarlas

@HktConfig(withVisibility = Visibility.Same)
public class ListT<t> implements __<ListT, t> {

  public final List<t> list;

  public ListT(List<t> list) {
    this.list = list;
  }
}

Una vez hecho esto ya podemos implementar nuestro funtor

class ListFunctor implements Functor<ListT> {

  @Override
  public <A, B> __<ListT, B> map(__<ListT, A> fa, Function<A, B> f) {
    List<B> listb = Hkt.asListT(fa).list.stream()
        .map(f)
        .collect(Collectors.toList());
    return new ListT<>(listb);
  }
}

Con esto podemos hacer poco por el momento pero segun avancen los articulos veremos como usarlo en nuestros desarrollos

Comparte este articuloShare on Facebook
Facebook
Tweet about this on Twitter
Twitter
Share on LinkedIn
Linkedin

Comentarios

comentarios