Clojure
Clojure e simplicidade
AVISO – me empolguei um pouco nessa postagem, para uma introdução mais gentil, verifique o post após esse.
Qualquer linguagem baseada em LISP, como Clojure, tem o mesmo problema: as pessoas falam de como a linguagem é fantástica, como ela revoluciona como você programa, até o momento em que você resolve entender por que. Aí você estuda a linguagem, aprende uma ou outra coisa, e não entende porque as pessoas falam tão bem dela.
Esse ciclo se repete várias vezes, e várias vezes, e você nunca entende o motivo das pessoas falarem tão bem. Até um dia em que você finalmente entende – e é aí que você vira uma dessas pessoas que falam bem, mas ninguém mais entende por que.
Clojure é, basicamente, um LISP que roda sobre a JVM. Porém, diferente de common LISP, Clojure possui duck typing – LISP não. É essa foi a primeira realização – tipagem dinâmica não implica em duck typing.
Ruby, JS, e Clojure possuem métodos (ou keywords, ou funções) que rodam sobre qualquer tipo que atenda aquele protocolo. for element in array
, por exemplo, roda em Ruby e JS da mesma maneira para Array
s, ou para Object
s (em JS) ou Hash
, Set
, para Ruby. Em Ruby, é porque todos implementam o método .to_a
. Já em Clojure, o nth
serve para pegar um elemento de uma coleção qualquer, seja ela uma List
ou Vector
, usando (nth ["some" "elements"] 1)
. E como é isso em Common LISP? Bom, se for uma List
, usa-se: (nth 1 '("some" "elements"))
. Se for um Vector
, com (aref (vector "some" "elements") 1)
. E assim por diante (o que quer que isso signifique nessa situação, já que nem posicionamento dos parâmetros nem nome das funções é consistente).
A segunda coisa interessante de Clojure é a sua “sintaxe”, ou na verdade, ausência de sintaxe. Na prática, a sintaxe não existe – você programa definido diretamente as S-Expressions, como se fosse uma lista de comandos. Por exemplo:
; uma definição de uma função (defn sum-ages [people] (reduce + (map :age people))) ; uma definição de uma lista `(defn sum-ages [people] (reduce + (map :age people)))
A segunda expressão, apenas pela presença de um “quote”, torna-se uma lista. O primeiro e segundo elementos são Symbol
, o terceiro elemento é um Vector
que contém outro Symbol
, e o quarto elemento é outra List
: (reduce + (map :age people))
, e assim as coisas continuam. Symbols, em Clojure, serão convertidos em sintaxe mais cedo ou mais tarde, então defn
será clojure.core/defn
, e chamará a função, símbolo, ou special-form desse nome mais cedo ou mais tarde. E isso é uma coisa fantástica pelos motivos que veremos a seguir. Mas o primeiro deles é bem óbvio: você não tem códigos – apenas dados. E como a linguagem é composta de dados, podemos manipulá-la, moldá-la, e alterá-la com macros. Além disso, Clojure é uma linguagem muito simples – ao contrário por exemplo, de Ruby, aonde a linguagem é complexa, mas programar nela é simples, em Clojure a linguagem é simples, mas programar nela é um pouco mais complicado.
E o motivo, por mais absurdo que pareça, é que nós, programadores, aprendemos a programar de forma errada
(more…)