Racket

Lisp além do Clojure

Ronie Uliana

Arquiteto de Software

Cientista de Dados

Essa talk NÃO...

  • Não é sobre Clojure
  • Não é sobre sacanear o Clojure
  • Não é sobre como você deveria usar outra linguagem

A talk É...

Sobre coisas que podem entrar em main stream (eu espero), de outra linguagem "Lisp-like":

Racket

Sobre Lisp-likes...

It's 2002, and programming languages have almost caught up with 1958.

Paul Graham

"Revenge of the Nerds"

Paul Graham

Lisp evolui

Clojure | Racket

(Common Lisp) => Clojure

  • Software Transactional Memory
  • Persistent Collections
  • Multimethods

(Lisp) => (Scheme) => Racket

  • Parameters
  • Custodians
  • Macros (Hygienic / Reader)
  • Modules
  • ...

Racket

Linguagem de programação programável

Foco

construir aplicações DSLs

(e então contruir aplicações)

... abordagem muito interessante!

Parameters

Como você faz...

  • Com configurações de banco de dados?
  • Com número de threads?
  • Com número máximo de iterações?

with-bindings? Globais? Singleton? Ler um arquivo de config no meio do código?

"sideband data"*

function arguments

*Avdi Grimm - Exceptional Ruby

Sideband data

#lang racket

(define number-of-threads
  (make-parameter 2))

(define (work)
  ;work hard!
  (displayln (number-of-threads)))

(work) 

(parameterize ([number-of-threads 42])
  (work))

(work)

Isso espalha?

Linguagens já tem "thread local".

Uso desencorajado :(

Configs são uma zona.

 

Racket parameters parecem:

- Fáceis

- Úteis

- Realmente fáceis

Parameters...

Custodians

Como você faz...

  • Para abrir e fechar arquivos?
  • Para abrir e fechar conexões?
  • Para iniciar e matar threads?
  • Para gerenciar recursos?

open/finally/close? ensure? using? with-open? 

Custodian

Fecha e limpa tudo...

(define (do-work a-function)
  (define cust (make-custodian))
  ...
  (parameterize ([current-custodian cust])
    (dynamic-wind
     (λ () ... inicializa
     (λ () ... faz algo/abre coisas
     (λ () (custodian-shutdown-all cust))))

File

Thread

Socket

?

Cust 1

Cust 2

Cust 3

Isso espalha?

Libera vários recursos em uma única chamada.

 

Racket custodians parecem:

- Seguro

- Fáceis

- Ainda não muito polidos

  ("dynamic-wind")

Custodians...

Macros

Hygienic (simples)

Pattern-based Macros

(define (hello b)
  (let ([a "Hello,"]
        [c "!"])
    (format "~a ~a~a" a b c)))

Eu acho...

"let" tem parênteses demais

e muito aninhamento

Pattern-based Macros

(define-syntax-rule (given (bind expr) ...)
  (begin
    (define bind expr) ...))
(define (hello b)
  (given [a "Hello, "]
         [c !])
  (format "~a ~a~a" a b c))

Pattern-based Macros

vamos exagerar um pouco :)

(define-syntax (given stx)
  (syntax-parse stx
    #:literals (=)
    [(_ bind = expr)
     #'(define bind expr)]
    [(_ bind = expr rest ...)
     #'(begin (define bind expr)
              (given rest ...))]))
(define (hello b)
  (given a = "Why"
         c = "???")
  (format "~a ~a~a" a b c))

Threading Macro

Racket style

#lang racket
(require threading)

(~>> '(100 200 300 400)
     (map add1)
     (take _ 2))

(~> '(100 200 300 400)
    (map add1 _)
    (take 2))

Isso espalha?

Macros são metaprogramação.

 

Racket macros parecem:

- Poderosas

- Simples Limpas

 

Rust já tem "Pattern-based macros".

Macros...

Macros

Reader... o_O

>_<

(regexp-match #px"\\d+" "123"

^_^

(regexp-match /\d+/ "123")

DEMO!

Isso espalha?

Linguagens não costumam deixar você definir literais.

 

Regexp, DateTime, Money, SQL, métricas, etc...

 

Racket reader macros são:

- Poderosas

- O jeito "certo"®

- Ainda falta polimento

Reader macros

Modules

  1. Arquivo = módulo (masomenos)

  2. Cada módulo ter em interface

  3. O módulo é o que ele !

Cada módulo

é uma linguagem

Module

Module

Não gosto de "define"

hate-define.rkt
#lang racket
(provide (except-out (all-from-out racket) define)
         (rename-out (define def)))
hate-define-use.rkt
#lang s-exp "hate-define.rkt"
(define add2 (λ (x) (+ x 2)))
   (def add2 (λ (x) (+ x 2)))

Reescrevendo #%app

Deixa eu mostrar um truque bacanudo :)

Reescrevendo %#app

Em Racket, toda aplicação de função usa #%app por baixo dos panos...

(add1 10)
...
(%#app add1 10)

Posso redefinir #%app com módulos

#lang racket
(provide (except-out (all-from-out racket) #%app)
         (rename-out [my-app #%app]))

(define-syntax-rule (my-app proc args ...)
  (begin
    (displayln proc)
    (#%app proc args ...)))
(add1 10)
...
(begin
  (displayln add1)
  (%#app add1 10))
(add1 10)
...
(%#app add1 10)

Isso espalha?

Namespaces, import, requires são meio bagunçados.

 

Cada linguagem faz de um jeito.

 

Racket modules parecem:

- Poderosos

- Simples

Modules!

Mais...

Phase Levels

Places (parallel processing)

Continuations (nothing new :p)

Contracts (Eiffel-like)

FFI

Dicas:

Racket não tem multimétodos, isso é meio estranho no começo (tem generics)

As coleções são meio... meh...  use: data/collections

Para aprender a criar linguagens:

http://beautifulracket.com

Degugging:

racket -l errortrace -t <prog>

Obrigado!

Ronie Uliana

ronie@vagas.com

@ronie

medium.com/@ronie

github.com/ruliana

Racket - Lisp além do Clojure

By Ronie Uliana

Racket - Lisp além do Clojure

O que há de novo em termos de linguagem de programação deve vir do Lisp (como sempre), mas não do Clojure e sim do Racket.

  • 2,833