Prelude AdvPL¶
Sobre o Prelude AdvPL¶
O Prelude AdvPL é uma biblioteca para AdvPL, escrita pela NG Informática
,
altamente compatível com Harbour, e que visa a implementação de conceitos
funcionais na linguagem e melhoria na qualidade de código. A biblioteca
implementa uma sintaxe expressiva e permite uma maior abstração do domínio da
aplicação, evitando boilerplate e código desnecessário, além de ter um cuidado
especial com a performance.
Através do pré-processador são implementadas features extras em cima da
linguagem, mas sem quebrar qualquer compatibilidade com código legado. O Prelude
AdvPL implementa três tipos de funções: Prelude Functions,
Cast Functions e Validate Functions. Prelude Functions são comumente
utilizadas para manipulação de dados, como listas, numéricos, strings ou blocos
de código, mas de uma forma muito mais expressiva. Cast Functions servem
para trabalhar em cima do sistema dinâmico de tipos da linguagem. Elas permitem
a redefinição explícita de tipos de valores em casos específicos.
Validate Functions servem para validar a coerência e consistência de dados.
Algumas de suas validações aceitáveis são CPF
, CNPJ
, Name
, Even
,
Odd
, entre outros.
Abstrações Sintáticas:
Intervalos Numéricos¶
O Prelude AdvPL implementa uma sintaxe própria para intervalos numéricos, evitando que sejam criadas instruções desnecessárias para tal, como loops.
Definição Formal¶
range ::= @{ <expr> [, <expr> ] .. <expr> } ;
Exemplos¶
Temos duas opções para intervalos numéricos: @{ x .. y }
, sendo x
o
valor inicial e y
o valor final; e @{ x, y .. z }
, sendo x
o valor
inicial, z
o valor final, seguindo num intervalo de y - x
. Exemplos:
1 2 3 4 5 6 7 8 | #include "prelude.ch"
Function TestInterval()
// aRange recebe { 1, 2, 3, 4, 5 }
Local aRange := @{ 1 .. 5 }
// aStepRange recebe { 1, 3, 5, 7, 9, 11, 13, 15 }
Local aStepRange := @{ 1, 3 .. 15 }
Return 0
|
Sintaxe Padrão¶
Abstrações sintáticas são implementadas para tornar o código mais compreensível. Chamadas abstraídas podem receber até 3 parâmetros e ser aninhadas dentro de outras chamadas.
Definição Formal¶
prelude-call ::= @<ident> { <expr> [, <expr> [, <expr> ] ] }
Exemplos¶
Vamos imaginar que queremos realizar a seguinte operação:
- Criar uma lista com os elementos de 1 a 50;
@{}
- Obter os 20 primeiros elementos desta;
@Take
- Mapear e dobrar o valor de cada elemento obtido;
@Map
- Mostrar ao usuário cada elemento em um
Alert
.@Each
Devemos fazer:
1 2 3 4 5 6 7 | #include "prelude.ch"
Function Prelude()
@Each { Fun (X) -> Alert( X ), ;
@Map { Fun (Y) -> Y * 2, ;
@Take { 20, @{ 1 .. 50 } } } }
Return 0
|
Blocos de Primeira Classe¶
O Prelude AdvPL também abstrai blocos de primeira classe em forma de funções de
primeira classe, utilizando uma sintaxe similar a OCaml
ou Livescript
.
Blocos são, por padrão, definidos em AdvPL como { |Param| Expression }
.
A única função dessa abstração é aplicar um syntactic sugar para
Fun ( Param ) -> Expression
.
Nota: Lambda ( Param ) -> Expression
também é válido.
Definição Formal¶
fun ::= Fun ( [ <ident> [, <ident> [, <ident> ] ] ] ) -> <expr>
lambda ::= Lambda ( [ <ident> [, <ident> [, <ident> ] ] ] ): <expr>
Exemplos¶
Vamos realizar alguns testes com operações simples:
1 2 3 4 5 6 7 8 | #include "prelude.ch"
Function TestBlocks()
Local bAdd := Fun ( X, Y ) -> X + Y
Local bToString := Lambda ( X ): Str( X )
Alert( Eval( bToString, Eval( bAdd, 10, 20 ) ) ) // => "30"
Return 0
|
Sintaxe para Casting¶
Implementamos uma sintaxe especial para facilitar a transição de tipos de dados.
Por padrão, os tipos suportados atualmente são Str
, Int
e Number
.
De maneira similar a generics em C#, os tipos são aplicados dentro de tags.
Definição Formal¶
casting ::= @Cast\< <type> \> <expr>
Exemplos¶
1 2 3 4 5 6 7 | #include "prelude.ch"
Function TestCasting()
Local nStrToNumber := @Cast<Int> "18" ; // => 18
, cNumberToStr := @Cast<Str> 19 ; // => "19"
, nFloatToInt := @Cast<Num> 15.4 // => 15
Return 0
|
Sintaxe Validate¶
Validate atua de maneira muito similar a Cast, recebendo, como parâmetro
entre as tags, o “tipo” a ser validado. As opções atualmente disponíveis são
CPF
, CNPJ
, Name
, Even
, Odd
, Positive
, Negative
,
CEP
e Email
.
Definição Formal¶
validate ::= @Validate\< <type> \> <expr>
Exemplos¶
1 2 3 4 5 6 7 8 | #include "prelude.ch"
Function ValidateTests()
@Validate<Email> "marcelocamargo@linuxmail.org" // => .T.
@Validate<CNPJ> "62645927000136" // => .T.
@Validate<CPF> "45896587466" // => .F.
@Validate<Name> "Marcelo Camargo" // => .T.
Return 0
|
Sintaxe Do ... In¶
Recebe dois identificadores de funções, aplica function-composition, isto é, une as duas funções e aplica à expressão recebida.
Definição Formal¶
Exemplos¶
1 2 3 4 5 | #include "prelude.ch"
Function TestDo()
Do Alert >>= Str In 68
Return
|
Aplicação de Bloco¶
Para facilitar a abstração, há aplicação de blocos (ou funções anônimas) para funções do Prelude AdvPL que recebam exatamente 2 argumentos. Por padrão, o argumento antes do operador é o valor ao qual o bloco será aplicado e o elemento posterior ao operador, o operando direito, será o bloco que será aplicado. É possível usar essa abstação para outras coisas, que não a aplicação de blocos, contudo, não é aconselhável.
Definição Formal¶
block-app ::= @<ident> <expr> ::= <expr>
Exemplos¶
1 2 3 4 5 6 7 8 | #include "prelude.ch"
Function BlockApp()
Local aList := @{ 1 .. 10 } ;
, bPrint := Fun ( X ) -> Alert( X )
@Each aList ::= bPrint
Return
|
Sintaxe de Retenção¶
Exatamente o oposto à aplicação de bloco. Recebe dois operandos entre Of
.
O primeiro operando será o valor que será retido e o segundo será o elemento
que terá seu valor retido. Pode ser usada para outras coisas além de retenção,
no entando, não é aconselhável por puras questões de legibilidade.
Definição Formal¶
of-op ::= @<ident> <expr> Of <expr>
Exemplos¶
1 2 3 4 5 6 7 | #include "prelude.ch"
Function TestOf()
Local aList := @{ 1 .. 50 }
@Take 5 Of aList // => { 1, 2, 3, 4, 5 }
Return
|
Sintaxe On¶
Aplicação de função. O operando à esquerda corresponde ao primeiro parâmetro, o operando central corresponde à função e o operando à direita corresponde ao segundo parâmetro.
Definição Formal¶
on ::= On <ident> <ident> <expr>
Exemplos¶
1 2 3 4 5 6 7 8 | #include "prelude.ch"
Function TestOn()
Local aRotina := { }
On aRotina aAdd { STR001, STR002, STR003, STR004 }
Return
|
Sintaxe Just¶
Se o último operando à direita for um valor diferente de Nil
, o operando
à esquerda recebe-o.
Definição Formal¶
just ::= Just <ident> -> <ident> Receives <expr>
Exemplos¶
1 2 3 4 5 6 7 | #include "prelude.ch"
Function TestJust( /* all optional */ nX, nY, nZ )
Just M->X Receives nX
Just M->Y Receives nY
Just M->Z Receives nZ
Return
|
Keywords e Operadores¶
Algumas palavras-chave e operadores foram adicionados como aliases para as já existentes, entre eles:
Keywords¶
Keyword | Correspondente | Token |
---|---|---|
Let | Local | T_LOCAL |
Extern | Private | T_PRIVATE |
True | .T. | T_TRUE |
False | .F. | T_FALSE |
Operadores¶
Operador | Correspondente | Token |
---|---|---|
<- | := | T_ASSIGNMENT |
Is | == | T_STRICTEQUALS |
Like | = | T_EQUALS |
Or | .Or. | T_OR |
And | .And. | T_AND |
~- | (... - 1) | T_LTADPOLE |
-~ | (... + 1) | T_RTADPOLE |
Operador Ternário¶
Foi implementado If como expressão, retornando valores, em sua equivalência
a IIf
, onde podemos fazer, por exemplo: Let cName <- If 1 < 2 Then "Foo" Else "Bar"
.
Operador Tadpole (Girino)¶
Um operador herdado de C++, é, respectivamente, a equivalência de ++
e --
para -~
e ~-
sem modificar o valor original das variáveis repassadas, onde, por exemplo, ~-cAge
equivale a cAge - 1
e
-~cAge
a cAge + 1
, tal que como analogia, faz se que o girino está nadando para “fora” ou para “dentro”
da variável, aplicando a ação determinada.
Gerenciador de Pacotes¶
Foi implementando um package manager, responsável, no momento, apenas por
identificação e versionamento de um determinado programa, baseando-se na sintaxe
Package <string>(Version: <number>) Where
, o que definirá, estaticamente,
Package
e _NVERSAO
, para uso interno.
Tipos de Funções:
Cast Functions¶
Cast Functions são funções padrão de conversão explícita de tipos.
-
@Cast<Int>
Retorna um valor numérico inteiro a partir de um valor numérico com parte inteira e decimal informado como parâmetro, desconsiderando todos os dígitos à direta do ponto decimal.
@Cast<Int> 87.2 // => 87
-
@Cast<Num>
Converte uma sequência de caracteres que contêm dígitos em um valor numérico.
@Cast<Num> "9587" // => 9587
-
@Cast<Str>
A partir de um numérico, esta função retorna uma string formatada, inserindo espaços (” ”) à esquerda e/ou o símbolo decimal (”.”) em suas casas, de acordo com a informação do parâmetro.
@Cast<Str> 987 // "987"
Prelude Functions¶
Prelude Functions são as mais importantes funções do Prelude AdvPL. Elas são basicamente responsáveis por toda manipulação de dados que ocorre. Estão definidas no núcleo da biblioteca e possuem uma sintaxe própria para uso.
-
Bool @All { Block, Array }
Retorna verdadeiro se todos os itens na lista são verdadeiros quando aplicados ao teste.
-
Bool @AndList { Array }
Retorna falso se qualquer item na lista é falso. Caso contrário, retorna verdadeiro.
-
Bool @Any { Block, Array }
Retorna verdadeiro se quaisquer dos itens da lista são verdadeiros. Caso contrário, retorna falso.
-
Array @Compact { Array }
Retorna uma lista contendo apenas os valores verdadeiros da lista recebida.
-
Array @Concat { Array }
Concatena uma lista de listas juntas, a um nível 1 de imersão.
-
Array @Each { Block, Array }
Aplica um bloco para cada elemento na lista e retorna a lista original. Retorna a própria lista, comumente utilizada para efeitos colaterais.
-
Array @EachIndex { Block, Array }
Similar, quase o mesmo comportamento que a função
@Each
, mas aplica-se com dois parâmetros, o elemento em questão e o índice deste. Isso é útil quando realmente precisa-se saber a posição em que o elemento se encontra.
-
Number @ElemIndex { Mixed, Array }
Retorna o índice da primeira ocorrência do elemento em questão. Retorna nulo caso nenhum elemento como o passado seja encontrado.
-
Array @ElemIndices { Mixed, Array }
Retorna uma array contendo todos os índices que correspondem ao elemento em questão. Retorna um array vazio caso nenhum elemento seja encontrado.
-
Bool @Even { Number }
Retorna se o número dado é par.
-
Array @Explode { String }
Transforma uma string em um array de caracteres.
-
Array @Filter { Block, Array }
Retorna uma nova lista composta de todos os itens que passam no teste do bloco dado.
-
Mixed @Find { Block, Array }
Retorna o primeiro item que passa no teste do bloco dado. Retorna nula caso todos os elementos falhem na aplicação do teste.
-
Number @FindIndex { Block, Array }
Retorna o índice do primeiro elemento a passar no predicado. Retorna nulo caso nenhum dos elementos passe no teste em questão.
-
Array @FindIndices { Block, Array }
Retorna um array contendo os índices dos elementos a passarem no predicado. Caso nenhum elemento passe no teste, retorna um array vazio.
-
Number @GCD { Number, Number }
Retorna um máximo denominador comum de dois números.
-
Mixed @Head { Array }
Retorna o primeiro item de um array.
-
Mixed @Id { Mixed }
Retorna o próprio elemento. Útil como placeholder.
-
Array @Initial { Array }
Retorna todos os itens de uma lista, exceto o último.
-
Number @LCM { Number, Number }
Retorna o mínimo múltiplo comum de dois números.
-
Array @Map { Block, Array }
Aplica um bloco para cada item em uma lista e produz uma nova lista com os resultados. O tamanho da lista retornada é igual ao da lista dada.
-
Array @MapIndex { Block, Array }
Quase o mesmo que
@Map
, contudo, aplica-se com dois parâmetros, ambos o item e o índice. É útil quando realmente precisa-se conhecer a posição onde o elemento se encontra. Retorna a lista modificada.
-
Mixed @Maximum { Array }
Percorre uma lista de itens comparáveis e retorna o maior deles.
-
Number @Mean { Array }
Retorna a média dos valores de uma lista.
-
Mixed @Minimum { Array }
Percorre uma lista de itens comparáveis e retorna o menos deles.
-
Number @Negate { Number }
A negação de um dado número.
-
Bool @Odd { Number }
Retorna se o dado número é ímpar.
-
Bool @OrList { Array }
Retorna verdadeiro se qualquer item da lista é verdadeiro. Caso contrário, retorna falso.
-
Array @Partition { Block, Array }
Equivalente a
{ @Filter { f, xs }, @Reject { f, xs } }
, mas mais eficiente, utilizando apenas um loop.
-
Number @Pi { }
Retorna os 16 primeiros números de pi.
-
Number @Product { Array }
Obtém o produto de todos os itens na lista.
-
Array @Range { Number, Number }
Recebe dois valores inteiros e retorna um array dentro daquele intervalo.
-
Number @Recipe { Number }
Retorna 1 divido pelo valor dado.
-
Array @Reject { Block, Array }
Como
@Filter
, mas a nova lista é composta de todos os itens que falham no teste da função.
-
Array @Reverse { Array }
Reverte e retorna uma lista.
-
Number @SigNum { Number }
Toma um número e retorna -1, 0 ou 1, isto dependendo do operador unário em questão do número (-, 0, +).
-
Array @Slice { Number, Number, Array }
Corta uma lista e retorna o pedaço dela, recebendo os valores inicial e final e a lista a ser cortada.
-
Array @Sort { Array }
Organiza em ordem ascendente uma lista. Não modifica a entrada.
-
Array @StepRange { Number, Number, Number }
Recebe três inteiros e retorno um array indo do primeiro número até o segundo e seguindo um intervalo do terceiro menos o primeiro.
-
Number @Sum { Array }
Soma todos os itens de uma lista e os retorna.
-
Array @Split { String, String }
Recebe um delimitador e uma string. Retorna um array separando a string pelo dado delimitador.
-
String @Stringify { Array }
Transforma um array de caracteres em uma string.
-
Array @Tail { Array }
Retorna todos, menos o último item de uma lista.
-
Array @Take { Number, Array }
Obtém os primeiros
n
elementos de uma lista.
-
Array @TakeWhile { Block, Array }
Obtém os primeiros elementos da lista até que algum deles falhe no teste do dado bloco.
-
Number @Tau { }
Retorna o valor de tau, isto é, 2 * pi.
-
Array @Zip { Array, Array }
Une elementos de duas listas de mesmo tamanho. Útil para simular dicionários.
-
Array @ZipWith { Block, Array, Array }
Une elementos de duas listas de mesmo tamanho aplicando um bloco a elas. Retorna um único array contendo o resultado.
Validate Functions¶
Validate Functions são funções gerais de validação. Todas devem ter como retorno um valor Booleano.
-
@Validate<CEP>
Retorna a validade de um CEP no formato “99999-999”.
@Validate<CEP> "88590-000" // .T.
-
@Validate<CNPJ>
Retorna a validade de um CNPJ (apenas números).
@Validate<CNPJ> "30226467000115" // .T.
-
@Validate<CPF>
Retorna a validade de um CPF (apenas números).
@Validate<CPF> "15985496883" // .F.
-
@Validate<Email>
Valida um e-mail segundo os padrões atuais.
@Validate<Email> "marcelocamargo@linuxmail.org" // .T.
-
@Validate<Even>
Valida a paridade de um número.
@Validate<Even> 15 // .F.
-
@Validate<Name>
Verifica se o nome é válido, composto apenas por caracteres latinos.
@Validate<Name> "Marcelo Haskell Camargo" // .T.
-
@Validate<Negative>
Validação de negatividade numeral.
@Validate<Negative> 15 // .F.
-
@Validate<Number>
Retorna se determinado valor é válido como numeral.
@Validate<Number> "15" // .T.
-
@Validate<Odd>
Retorna se um número é ímpar.
@Validate<Odd> 15 // .T.
-
@Validate<Positive>
Validação de positividade numeral.
@Validate<Positive> 15 // .T.
Informações?
Marcelo Camargo <marcelo.camargo@ngi.com.br> <marcelocamargo@linuxmail.org>
Última modificação por Marcelo Camargo às 15:02 do dia 08/04/2015.