Eine Kleine Nachtmusik
Oz é uma linguagem estranha. Seus conceitos fundamentais são uma mistura de programação imperativa, funcional e lógica, além de programação concorrente e distribuída. Intrinsecamente multi-paradigma.
Terminei os dois primeiros capítulos do CTMCP e ainda fica um certo estranhamento, até porque no começo parece tanto com uma linguagem funcional. Mas tem unificação, valores parciais e outras coisas estranhas que parecem Prolog.
Para exemplificar, vamos começar com algum background: Oz é dividida em uma kernel language que abriga os conceitos fundamentais, e uma full language que inclui sintaxe extra e outras conveniências. A kernel language é simples e é nela que se define a semântica da linguagem; além disso, especifica-se formalmente como traduzir programas na full language para a kernel language, e assim é possível especificar a semântica de qualquer programa na linguagem completa.
Pois bem, a kernel language define procedimentos, e não funções, como conceitos primitivos. Funções são uma abstração sintática da linguagem completa, que são traduzidas para procedimentos na kernel language. Como exemplo, a função
O
Note-se aí a atribuição do resultado (
Estranho, mas interessante.
Terminei os dois primeiros capítulos do CTMCP e ainda fica um certo estranhamento, até porque no começo parece tanto com uma linguagem funcional. Mas tem unificação, valores parciais e outras coisas estranhas que parecem Prolog.
Para exemplificar, vamos começar com algum background: Oz é dividida em uma kernel language que abriga os conceitos fundamentais, e uma full language que inclui sintaxe extra e outras conveniências. A kernel language é simples e é nela que se define a semântica da linguagem; além disso, especifica-se formalmente como traduzir programas na full language para a kernel language, e assim é possível especificar a semântica de qualquer programa na linguagem completa.
Pois bem, a kernel language define procedimentos, e não funções, como conceitos primitivos. Funções são uma abstração sintática da linguagem completa, que são traduzidas para procedimentos na kernel language. Como exemplo, a função
fun {Times2 N}é traduzida para o procedimento
N * 2
end
proc {Times2 N ?R}
R = N * 2
end
O
?R
é um parâmetro de saída que é atribuído com o resultado de retorno do procedimento (se houver um). O que era funcional vira imperativo na kernel language. O que é realmente interessante é a forma como isso interage com valores parciais e estruturas de dados. Vamos definir uma função Map
que aplica uma função F
a cada elemento de uma lista L
. O operador |
é o construtor de lista (cons
em Scheme/Lisp, ::
em ML, :
em Haskell); {F H}
é uma chamada da função F
com argumento H
; case
faz pattern matching. Logo após a função tem a tradução dela para a kernel language.
fun {Map F L}
case L of H | T then {F H} | {Map F T}
else nil end
end
proc {Map F L ?R}
case L of H | T then
local Rr in
R = {F H} | Rr
{Map F T Rr}
end
else nil end
end
Note-se aí a atribuição do resultado (
R
) a um valor parcial, pois Rr
(o "resto" do resultado) ainda não possui valor. O efeito disso é transformar uma função que não é tail recursive em um procedimento que é. O programador ganha automaticamente os benefícios da recursão final (tradução tentativa para tail recursion), sem se preocupar com isso.
Estranho, mas interessante.
0 Comments:
Post a Comment
<< Home