DEV Community

Zoey de Souza Pessanha
Zoey de Souza Pessanha

Posted on

Sintaxe e especificação da linguagem Nix

Com o Nix devidamente apresentado no post anterior, agora irei introduzir a
sintaxe da linguagem!

Este artigo foi feito com a intenção de traduzir, resumidamente, a especificação oficial
da linguagem que pode ser encontrada no link no final do post.

Paradigmas da linguagem

"Preguiçosa"

Isso significa que as expressões somente são executadas caso realmente sejam necessárias.

Neste exemplo, a função abort nunca será executada:

let
  a = abort "nunca irá acontecer";
  b = "olá";
  c = "mundo";
in b + c
Enter fullscreen mode Exit fullscreen mode

Funcional

Programação Funcional é um paradigma de linguagens de computação onde a estrutura e elementos de
um programa são tratados como expressões matemáticas, evitando a mutabilidade de estado. Linguagens
funcionais também tendem a fazer parte do paradigma declarativo, onde a construção do programa
é baseado em expressões.

Pura

Definimos uma função como pura quando o retorno dela é unicamente definido pelos seus argumentos
de entrada, ou seja, não há efeitos colaterais externos ou "observáveis".

Especificação da linguagem

Expressões

Quando um tutorial referencia uma expressão Nix, significa que ele está descrevendo a
definição de uma função com várias entradas. Porém, uma expressão Nix pode ser definida como
um simples texto, até uma função ou um conjunto de outras expressões!

Tipos primitivos

Texto

Pode ser definido com aspas duplas " ou duas aspas simples '' para mais de uma linha:

# também suportam interpolações
"Diga ${pkgs.hello.name}"

''primeira linha
  segunda linha
''
Enter fullscreen mode Exit fullscreen mode

Números

Existem os tipos interios e ponto de fltuação que possuem precisão limitada:

5

1.18
Enter fullscreen mode Exit fullscreen mode

Caminhos

Caminhos relativos serão convertidos em absolutos quando a expressão for executada:

./ola/mundo
# /caminho/asbsoluto/para/ola/mundo

<nixpkgs/lib>
# /caminho/para/nixpkgs/lib
Enter fullscreen mode Exit fullscreen mode

URIs

URIs podem ser representadas independentemente, como:

let
  uri = https://github.com/Mdsp9070/dotfiles 
in fetchTarball { src = uri }
Enter fullscreen mode Exit fullscreen mode

Booleanos

Também existem os booleanos true e false.

Nulidade

A nulidade é representada pela expressão null.

Funções

Todas as funções são anônimas com o formato: argumento: expressão-Nix, como: x: x * x.

Caso queira nomear a função, você pode declarar: quadrado = x: x * x. E para executar essa
função com argumento: quadrado 3;

Múltiplos argumentos podem ser exigidos no formato: arg1: arg2: expressão-Nix.

É comum que Conjuntos sejam passados como argumentos para funções, e é possível referenciar apenas
os argumentos necessários:

a_e_b = conjunto: conjunto.a + conjunto.b

a_e_b { a = "ola"; b = "mundo"; }

# pode ser reescrita dessa maneira:
a_e_b = {a, b}: a + b
Enter fullscreen mode Exit fullscreen mode

Também é possível definir argumentos padrões:

soma = { a ? 1, b ? 2 }: a + b

soma {}
# 3

soma { a = 3; }
# 5
Enter fullscreen mode Exit fullscreen mode

Caso um argumento não declarado no cabeçalho da função seja fornecido, ocorrerá um erro, porém
isso pode ser evitado caso use reticências ...:

soma = { a, b }: a + b
soma { a = 5; b = 2; c = 10; }
# error: anonymous function at (string):1:2 called with unexpected argument 'c', at (string):1:1

soma = { a, b, ... }: a + b
soma { a = 5; b = 2; c = 10; }
# 7
Enter fullscreen mode Exit fullscreen mode

Você também pode referenciar todos os argumentos num Cojunto com a notação @:

soma = args@{ a, b, ... }: a + b + args.c
soma { a = 5; b = 2; c = 10; }
# 17
Enter fullscreen mode Exit fullscreen mode

Listas

É um conjunto de diversos valores separados por espaços em branco, que podem ter vários tipos:

[ 123 ./exemplo.nix "abc" (f { x = y; }) ]
Enter fullscreen mode Exit fullscreen mode

Define uma lista com quatro elementos. Note que a função f está dentro parênteses, caso contrário,
haveria cinco elementos na lista, sendo o quarto uma função f previamente declarada e o quinto um
conjunto.

Os valores de uma lista são "preguiçosos", mas seu tamanho não.

Conjuntos

Esta estrutura é o coração da linguagem, já que o foco principal é criar derivações, que são apenas conjuntos
de atributos que são passados para scripts construtores.

Conjuntos são estrutas de nome/valor definidos dentro de chaves:

{ x = 123;
  texto = "hello";
  y = f { tudo = 42; };
}
Enter fullscreen mode Exit fullscreen mode

A ordem dos atributos não é importante e é uma boa prática não haver repetições nos nomes das chaves.

Cada atributo pode ser acessado com o operador .:

{ a = "Foo"; b = "Bar" }.a
Enter fullscreen mode Exit fullscreen mode

Retorna "Foo". Também é possível definir um valor padrão caso um atributo não exista com a palavra-chave or:

{ a = "Foo"; b = "Bar" }.c or "xyz"
Enter fullscreen mode Exit fullscreen mode

As chaves também podem ser definidas por textos entre aspas duplas ":

{ "exemplo de ${chave}" = "Foo"; }."exemplo de ${chave}"
Enter fullscreen mode Exit fullscreen mode

Caso a chave de atributo tenha o valor nulo, o atributo não é executado:

{ ${if exemplo then "bar" else null} = true; }
Enter fullscreen mode Exit fullscreen mode

Retorna {} caso exemplo seja falso.

Conjuntos podem ter chaves que referem-se umas às outras com o construtor rec:

rec {
  x = y;
  y = 123l
}.x
Enter fullscreen mode Exit fullscreen mode

Operadores

# acesso
e . atributo

# chamada de função
e1 e2

# negação numérica
-e

# testa a existência de um atributo
e ? atributo

# concatenação de listas
e1 ++ e2

# multiplicação numérica
e1 * e2

# divisão numérica
e1 / e2

# soma numérica
e1 + e2

# subtração
e1 - e2

# operadores relacionais
e1 > e2
e1 >= e2
e1 < e2
e1 <= e2
e1 == e2
e1 != e2

# operadores booleanos
!e
e1 && e2
e1 || e2
e1 -> e2 # equivalente a !e1 || e2

# concatenação de conjuntos
e1 // e2
Enter fullscreen mode Exit fullscreen mode

Importações

import carrega, valida e importa expressões Nix a partir de um caminho, a palavra-chave não faz parte da linguagem em si:

x = import <nixpkgs> {}
y = trace x.pkgs.hello.name x;
Enter fullscreen mode Exit fullscreen mode

Construtores

with

O construtor with introduz o escopo léxico da expressão referenciada na próxima expressão:

let
  conjunto = { a = 1; b = 2 };
in
  with conjunto; "Tenho acesso aos atributos ${toString a} e ${toString b}"
Enter fullscreen mode Exit fullscreen mode

Pode ser muito útil nas expressões onde há necessidade de repetição de um atributo:

{ pkgs, ... }:

{
  buildInputs = with pkgs; [ curl rust bat ffmpeg ];
}

# ao invés de
{
  buildInputs = [ pkgs.curl pkgs.rust pkgs.bat pkgs.ffmpeg ];
}
Enter fullscreen mode Exit fullscreen mode

let...in

Permite a crição de variáveis locais:

let
  a = 2;
  b = 3;
in a + b
# 5
Enter fullscreen mode Exit fullscreen mode

inherit

Traz o escopo léxico externo para um interno:

buildPythonPackage rec {
  pname = "ola";
  version = "1.0";
  src = fetchPypi {
    inherit pname version;
   sha256 = "01ba..0";
  };
}
Enter fullscreen mode Exit fullscreen mode

Conclusão

Este artigo é uma tentativa de tornar a documentação do Nix acessível em português! Sempre irei
referenciar as fontes oficiais no final de cada artigo, junto com alguns recursos adicionais!

Fontes e recursos adicionais

Este post foi publicado com minha ferramenta de linha de comando devit!
Você pode encontrar instruções para instalação neste link.

Latest comments (0)