Scheme é um dialeto minimalista da linguagem de programação Lisp, projetado para facilitar um estilo de programação funcional enquanto promove uma sintaxe simples e limpa. É caracterizado pelo uso de parênteses, um poderoso sistema de macros e uma forte ênfase em recursão e procedimentos de primeira classe. A linguagem incentiva um paradigma de programação funcional e suporta várias técnicas de programação, incluindo programação funcional, imperativa e lógica.
Scheme foi criado na década de 1970 por Gerald Jay Sussman e Guy L. Steele Jr. no Instituto de Tecnologia de Massachusetts (MIT). Foi desenvolvido como uma tentativa de simplificar e melhorar a linguagem Lisp original, que havia se tornado complexa ao longo do tempo. A motivação por trás do Scheme era criar uma linguagem que fosse mais fácil de implementar e ensinar, mas ainda poderosa o suficiente para expressar ideias complexas.
Ao longo dos anos, o Scheme passou por várias revisões e esforços de padronização. Os padrões mais notáveis são os RnRS (Relatórios Revisadosn sobre a Linguagem Algorítmica Scheme), que formalizaram a linguagem e suas características. A comunidade Scheme continuou a desenvolver a linguagem, levando a novos padrões como R6RS e R7RS, que introduziram novos recursos e melhorias.
Atualmente, o Scheme continua popular em ambientes acadêmicos, particularmente na educação em ciência da computação, devido à sua elegância e sintaxe limpa. Sua influência pode ser vista em muitas linguagens de programação e paradigmas modernos. O Scheme é frequentemente associado à comunidade de programação funcional e inspirou linguagens como Clojure e Racket, que se basearam em seus princípios e ampliaram suas capacidades.
Scheme utiliza uma sintaxe totalmente parental onde o código é escrito em notação prefixa; por exemplo, uma operação de adição é escrita como (+ 1 2)
.
Funções em Scheme são cidadãos de primeira classe, o que significa que podem ser passadas como argumentos ou retornadas de outras funções. Exemplo:
(define (make-adder x)
(lambda (y) (+ x y)))
(define add5 (make-adder 5))
(add5 10) ; retorna 15
Scheme suporta otimização de chamada de cauda, permitindo que funções reutilizem o quadro de pilha atual para chamadas recursivas que ocorrem na posição de cauda, prevenindo estouro de pilha.
Scheme permite o uso de continuações, permitindo que programadores capturem o estado atual da computação e manipulem o fluxo de controle:
(call-with-current-continuation
(lambda (exit)
(exit 'done)))
Scheme possui um poderoso sistema de macros que permite aos programadores criar extensões sintáticas. Uma macro simples pode ser definida da seguinte forma:
(define-syntax my-if
(syntax-rules ()
((_ test then else)
(if test then else))))
Scheme suporta abstração de dados através de estruturas como listas, pares e funções de ordem superior, permitindo manipulação eficiente de dados.
Scheme emprega escopo lexical, onde o escopo de uma variável é determinado por sua localização física no código-fonte. Isso leva a um comportamento previsível em relação às ligações de variáveis.
Scheme é tipado dinamicamente, permitindo que variáveis mantenham valores de qualquer tipo sem a necessidade de declarações de tipo explícitas.
Como um dialeto Lisp, Scheme é otimizado para processamento de listas, facilitando a realização de operações em listas:
(define my-list (list 1 2 3 4))
(car my-list) ; retorna 1
(cdr my-list) ; retorna (2 3 4)
Funções em Scheme podem ser definidas recursivamente com posição de cauda para otimizar o uso de memória e desempenho. Por exemplo:
(define (factorial n)
(define (fact-helper n acc)
(if (zero? n)
acc
(fact-helper (- n 1) (* n acc))))
(fact-helper n 1))
Aplicações Scheme podem geralmente ser construídas usando o ambiente de execução da implementação escolhida. Por exemplo, no Racket, você pode usar a ferramenta de linha de comando racket
para executar arquivos .rkt
ou compilá-los em executáveis.
Vários compiladores e interpretadores estão disponíveis para Scheme, incluindo:
Scheme é amplamente utilizado na academia para ensinar princípios de programação e como uma ferramenta para pesquisa em ciência da computação. Tem aplicações em inteligência artificial, design de linguagens e scripting, bem como em vários domínios que requerem computação simbólica ou manipulação complexa de dados.
Ambas as linguagens suportam um estilo de programação funcional, mas Python enfatiza legibilidade e simplicidade, enquanto Scheme foca em expressões poderosas e concisas. A sintaxe rica em parênteses do Scheme pode ser vista como uma barreira para iniciantes, enquanto a sintaxe baseada em indentação do Python é geralmente mais acessível.
JavaScript também suporta programação funcional e possui funções de primeira classe. No entanto, JavaScript tem um sistema de objetos baseado em protótipos, enquanto Scheme se baseia em paradigmas funcionais. O sistema de macros do Scheme oferece capacidades não presentes no JavaScript.
C é uma linguagem de baixo nível, estaticamente tipada, projetada para programação de sistemas, enquanto Scheme é de alto nível e dinamicamente tipada. C foca em desempenho e manipulação em nível de hardware, enquanto Scheme enfatiza abstração e aspectos teóricos da computação.
Ambas as linguagens estão enraizadas na programação funcional. Haskell usa um sistema de tipos mais rígido e suporta avaliação preguiçosa, enquanto a tipagem dinâmica e a avaliação ansiosa do Scheme permitem uma programação mais flexível à custa de algum desempenho.
Ruby é uma linguagem de programação orientada a objetos que mistura recursos de programação funcional, enquanto Scheme é puramente funcional. A sintaxe do Ruby é mais verbosa, enquanto a simplicidade do Scheme vem de seu design minimalista.
A tradução de código Scheme para outras linguagens pode ser facilitada por ferramentas que entendem tanto a sintaxe do Scheme quanto a linguagem de destino. Algumas ferramentas úteis de tradução de código de fonte para fonte incluem:
Chicken Scheme fornece um compilador que pode traduzir código Scheme para C, tornando possível aproveitar bibliotecas C e criar executáveis eficientes.
Racket, um derivado do Scheme, possui capacidades integradas para transformar e compilar código em JavaScript, facilitando a implementação de aplicações web.
Gambit Scheme pode compilar código Scheme em C e executáveis nativos, proporcionando opções de tradução eficientes para aplicações críticas em desempenho.