mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 17:41:41 +00:00
394 lines
10 KiB
Markdown
394 lines
10 KiB
Markdown
|
---
|
|||
|
filename: learn.nix
|
|||
|
contributors:
|
|||
|
- ["Chris Martin", "http://chris-martin.org/"]
|
|||
|
- ["Rommel Martinez", "https://ebzzry.io"]
|
|||
|
- ["Javier Candeira", "https://candeira.com/"]
|
|||
|
translators:
|
|||
|
- ["Loïc Reynier", "https://github.com/loicreynier"]
|
|||
|
---
|
|||
|
|
|||
|
Nix est un langage fonctionnel développé pour
|
|||
|
le gestionnaire de paquet [Nix](https://nixos.org/nix/) et
|
|||
|
[NixOS](https://nixos.org/).
|
|||
|
|
|||
|
Les expressions Nix peuvent être évaluées avec
|
|||
|
[nix-instantiate](https://nixos.org/nix/manual/#sec-nix-instantiate)
|
|||
|
ou [`nix repl`](https://nixos.org/nix/manual/#ssec-relnotes-2.0).
|
|||
|
|
|||
|
```nix
|
|||
|
with builtins; [
|
|||
|
|
|||
|
# Commentaires
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Ceci est un commentaire en ligne.
|
|||
|
|
|||
|
/* Ceci est un commentaire
|
|||
|
écrit sur plusieurs lignes. */
|
|||
|
|
|||
|
|
|||
|
# Booléens
|
|||
|
#=========================================
|
|||
|
|
|||
|
(true && false) # Et
|
|||
|
#=> false
|
|||
|
|
|||
|
(true || false) # Ou
|
|||
|
#=> true
|
|||
|
|
|||
|
(if 3 < 4 then "a" else "b") # Test logique
|
|||
|
#=> "a"
|
|||
|
|
|||
|
|
|||
|
# Entiers et nombres flottants
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Il y a deux types de nombres : les entiers et les flottants.
|
|||
|
|
|||
|
1 0 42 (-3) # Quelques exemples d'entiers
|
|||
|
|
|||
|
123.43 .27e13 # Quelques exemples de nombre flottants
|
|||
|
|
|||
|
# Les opérations conservent le type du nombre
|
|||
|
|
|||
|
(4 + 6 + 12 - 2) # Addition
|
|||
|
#=> 20
|
|||
|
(4 - 2.5)
|
|||
|
#=> 1.5
|
|||
|
|
|||
|
(7 / 2) # Division
|
|||
|
#=> 3
|
|||
|
(7 / 2.0)
|
|||
|
#=> 3.5
|
|||
|
|
|||
|
|
|||
|
# Chaînes de caractères
|
|||
|
#=========================================
|
|||
|
|
|||
|
"Les chaînes de caractères littérales sont écrites entre guillements."
|
|||
|
|
|||
|
"
|
|||
|
Les chaînes de caractères littérales
|
|||
|
peuvent s'étendre sur
|
|||
|
plusieurs lignes
|
|||
|
"
|
|||
|
|
|||
|
''
|
|||
|
Ceci est ce qu'on appelle une
|
|||
|
"chaîne de caractères littérale indentée".
|
|||
|
Les espaces de début de lignes sont intelligemment supprimées.
|
|||
|
''
|
|||
|
|
|||
|
''
|
|||
|
a
|
|||
|
b
|
|||
|
''
|
|||
|
#=> "a\n b"
|
|||
|
|
|||
|
("ab" + "cd") # Concaténation de chaînes de caractères
|
|||
|
#=> "abcd"
|
|||
|
|
|||
|
# L'antiquotation vous permet d'intégrer des valeurs
|
|||
|
# dans des chaînes de caracères.
|
|||
|
("Votre répertoire personnel est ${getEnv "HOME"}")
|
|||
|
#=> "Votre répertoire personnel est /home/alice"
|
|||
|
|
|||
|
|
|||
|
# Chemins
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Nix a un type de variable primitif pour les chemins.
|
|||
|
/tmp/tutorials/learn.nix
|
|||
|
|
|||
|
# Un chemin relatif est résolu en un chemin absolu
|
|||
|
# au moment de l'évaluation.
|
|||
|
tutorials/learn.nix
|
|||
|
#=> /the-base-path/tutorials/learn.nix
|
|||
|
|
|||
|
# Un chemin doit toujours contenir au moins une barre oblique (slash).
|
|||
|
# Un chemin relatif d'un fichier dans le répertoire courant
|
|||
|
# a donc besoin du préfixe `./`
|
|||
|
./learn.nix
|
|||
|
#=> /the-base-path/learn.nix
|
|||
|
|
|||
|
# L'opérateur `/` doit être entouré d'espaces afin d'être
|
|||
|
# traité comme une division
|
|||
|
7/2 # Ceci est un chemin
|
|||
|
(7 / 2) # Ceci est une division entière
|
|||
|
|
|||
|
|
|||
|
# Importations
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Un fichier nix contient une seule expression principale sans
|
|||
|
# variable libre.
|
|||
|
# Une expression importée s'évalue à la valeur du fichier importé.
|
|||
|
(import /tmp/foo.nix)
|
|||
|
|
|||
|
# Les importations peuvent également être spécifiées par des chaînes
|
|||
|
# de caractères.
|
|||
|
(import "/tmp/foo.nix")
|
|||
|
|
|||
|
# Les chemins doivent être absolus. Cependant comme les chemins
|
|||
|
# relatifs sont automatiquement résolus, ils peuvent être utilisés
|
|||
|
# pour l'importation.
|
|||
|
(import ./foo.nix)
|
|||
|
|
|||
|
# Attention, cela ne se produit pas avec les chaînes de caractères.
|
|||
|
(import "./foo.nix")
|
|||
|
#=> error: string ‘foo.nix’ doesn't represent an absolute path
|
|||
|
|
|||
|
|
|||
|
# Let
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Les blocs `let` permettent d'affecter des valeurs avec des variables.
|
|||
|
(let x = "a"; in
|
|||
|
x + x + x)
|
|||
|
#=> "aaa"
|
|||
|
|
|||
|
# Les affectations peuvent se référer les unes aux autres, et leur ordre
|
|||
|
# n'a pas d'importance.
|
|||
|
(let y = x + "b";
|
|||
|
x = "a"; in
|
|||
|
y + "c")
|
|||
|
#=> "abc"
|
|||
|
|
|||
|
|
|||
|
# Les affectations d'un bloc fille écrasent les affections du bloc mère.
|
|||
|
(let a = 1; in
|
|||
|
let a = 2; in
|
|||
|
a)
|
|||
|
#=> 2
|
|||
|
|
|||
|
|
|||
|
# Fonctions
|
|||
|
#=========================================
|
|||
|
|
|||
|
(n: n + 1) # Fonction qui ajoute 1
|
|||
|
|
|||
|
((n: n + 1) 5) # Fonction précédente appliquée à 5
|
|||
|
#=> 6
|
|||
|
|
|||
|
# Il n'y a pas de syntaxe pour nommer les fonctions,
|
|||
|
# mais elles peuvent affectée à une variable par un bloc `let`
|
|||
|
# comme toutes les autres valeurs.
|
|||
|
(let succ = (n: n + 1); in succ 5)
|
|||
|
#=> 6
|
|||
|
|
|||
|
# Une fonction a exactement un seul argument.
|
|||
|
# Des fonctions à plusieurs arguments peuvent être construites
|
|||
|
# par imbrificication de fonctions.
|
|||
|
((x: y: x + "-" + y) "a" "b")
|
|||
|
#=> "a-b"
|
|||
|
|
|||
|
# Il est également possible d'avoir des arguments de fonction nommés.
|
|||
|
# Nous verrons comment après avoir introduit les ensembles.
|
|||
|
|
|||
|
|
|||
|
# Listes
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Les listes sont indiquées par des crochets.
|
|||
|
|
|||
|
(length [1 2 3 "x"])
|
|||
|
#=> 4
|
|||
|
|
|||
|
([1 2 3] ++ [4 5])
|
|||
|
#=> [1 2 3 4 5]
|
|||
|
|
|||
|
(concatLists [[1 2] [3 4] [5]])
|
|||
|
#=> [1 2 3 4 5]
|
|||
|
|
|||
|
(head [1 2 3])
|
|||
|
#=> 1
|
|||
|
(tail [1 2 3])
|
|||
|
#=> [2 3]
|
|||
|
|
|||
|
(elemAt ["a" "b" "c" "d"] 2)
|
|||
|
#=> "c"
|
|||
|
|
|||
|
(elem 2 [1 2 3])
|
|||
|
#=> true
|
|||
|
(elem 5 [1 2 3])
|
|||
|
#=> false
|
|||
|
|
|||
|
(filter (n: n < 3) [1 2 3 4])
|
|||
|
#=> [ 1 2 ]
|
|||
|
|
|||
|
|
|||
|
# Ensembles
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Un ensemble, ou "set", est un dictionnaire non ordonné avec des clés
|
|||
|
# en chaîne de caractères.
|
|||
|
{ foo = [1 2]; bar = "x"; }
|
|||
|
|
|||
|
# L'opérateur `.` extrait une valeur d'un ensemble.
|
|||
|
{ a = 1; b = 2; }.a
|
|||
|
#=> 1
|
|||
|
|
|||
|
# L'opérateur `?` teste si la clé est présente dans l'ensemble.
|
|||
|
({ a = 1; b = 2; } ? a)
|
|||
|
#=> true
|
|||
|
({ a = 1; b = 2; } ? c)
|
|||
|
#=> false
|
|||
|
|
|||
|
# L'opérateur `//` fusionne deux ensembles.
|
|||
|
({ a = 1; } // { b = 2; })
|
|||
|
#=> { a = 1; b = 2; }
|
|||
|
|
|||
|
# Les valeurs de droite écrasent les valeurs de gauche.
|
|||
|
({ a = 1; b = 2; } // { a = 3; c = 4; })
|
|||
|
#=> { a = 3; b = 2; c = 4; }
|
|||
|
|
|||
|
# Le mot clé `rec` indique un ensemble récursif, ou "recursive set",
|
|||
|
# dans lequel les attributs peuvent se référer les uns aux autres.
|
|||
|
(let a = 1; in { a = 2; b = a; }.b)
|
|||
|
#=> 1
|
|||
|
(let a = 1; in rec { a = 2; b = a; }.b)
|
|||
|
#=> 2
|
|||
|
|
|||
|
# Les ensembles imbriqués peuvent être définis par morceaux.
|
|||
|
{
|
|||
|
a.b = 1;
|
|||
|
a.c.d = 2;
|
|||
|
a.c.e = 3;
|
|||
|
}.a.c
|
|||
|
#=> { d = 2; e = 3; }
|
|||
|
|
|||
|
# Les ensembles sont immuables, il est donc impossible de rédéfinir
|
|||
|
# un attribut :
|
|||
|
{
|
|||
|
a = { b = 1; };
|
|||
|
a.b = 2;
|
|||
|
}
|
|||
|
#=> attribute 'a.b' at (string):3:5 already defined at (string):2:11
|
|||
|
|
|||
|
# Cependant un attribut d'un attribut de l'ensemble peut également
|
|||
|
# être défini par morceaux même si l'attribut père a été directement
|
|||
|
# défini.
|
|||
|
{
|
|||
|
a = { b = 1; };
|
|||
|
a.c = 2;
|
|||
|
}
|
|||
|
#=> { a = { b = 1; c = 2; }; }
|
|||
|
|
|||
|
|
|||
|
# With
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Le corps d'un bloc `with` est évalué avec
|
|||
|
# les mappings d'un ensemble liés à des variables.
|
|||
|
(with { a = 1; b = 2; };
|
|||
|
a + b)
|
|||
|
# => 3
|
|||
|
|
|||
|
# Les affectations d'un bloc fille écrasent les affections du bloc mère.
|
|||
|
(with { a = 1; b = 2; };
|
|||
|
(with { a = 5; };
|
|||
|
a + b))
|
|||
|
#=> 7
|
|||
|
|
|||
|
# La première ligne du tutoriel commence par `with builtins;`
|
|||
|
# car `builtins` est un ensmble qui contient toutes les fonctions
|
|||
|
# de base (`length`, `head`, `tail`, `filter`, etc.). Cela permet
|
|||
|
# de ne pas avoir à écrire `builtins.length` au lieu de simplement
|
|||
|
# `length` par exemple.
|
|||
|
|
|||
|
|
|||
|
# Modèles d'ensemble
|
|||
|
#=========================================
|
|||
|
|
|||
|
# Les ensembles sont utiles pour passer plusieurs valeurs
|
|||
|
# à une fonction.
|
|||
|
(args: args.x + "-" + args.y) { x = "a"; y = "b"; }
|
|||
|
#=> "a-b"
|
|||
|
|
|||
|
# On peut l'écrire plus clairement en utilisant des modèles d'ensemble,
|
|||
|
# ou "set patterns".
|
|||
|
({x, y}: x + "-" + y) { x = "a"; y = "b"; }
|
|||
|
#=> "a-b"
|
|||
|
|
|||
|
# Par défaut, le modèle échoue si l'ensemble contient des clés
|
|||
|
# supplémentaires.
|
|||
|
({x, y}: x + "-" + y) { x = "a"; y = "b"; z = "c"; }
|
|||
|
#=> error: anonymous function called with unexpected argument ‘z’
|
|||
|
|
|||
|
# L'ajout de `, ...` permet d'ignorer les clés supplémentaires.
|
|||
|
({x, y, ...}: x + "-" + y) { x = "a"; y = "b"; z = "c"; }
|
|||
|
#=> "a-b"
|
|||
|
|
|||
|
|
|||
|
# Erreurs
|
|||
|
#=========================================
|
|||
|
|
|||
|
# `throw` provoque l'abandon de l'évaluation avec un message d'erreur.
|
|||
|
(2 + (throw "foo"))
|
|||
|
#=> error: foo
|
|||
|
|
|||
|
# `tryEval` permet de capturer les erreurs.
|
|||
|
(tryEval 42)
|
|||
|
#=> { success = true; value = 42; }
|
|||
|
(tryEval (2 + (throw "foo")))
|
|||
|
#=> { success = false; value = false; }
|
|||
|
|
|||
|
# `abort` est comme `throw`, mais l'erreur est alors fatale :
|
|||
|
# elle ne peut pas être capturée.
|
|||
|
(tryEval (abort "foo"))
|
|||
|
#=> error: evaluation aborted with the following error message: ‘foo’
|
|||
|
|
|||
|
# `assert` s'évalue à la valeur donnée si le test est vrai;
|
|||
|
# sinon il lève une exception capturable.
|
|||
|
(assert 1 < 2; 42)
|
|||
|
#=> 42
|
|||
|
(assert 1 > 2; 42)
|
|||
|
#=> error: assertion failed at (string):1:1
|
|||
|
(tryEval (assert 1 > 2; 42))
|
|||
|
#=> { success = false; value = false; }
|
|||
|
|
|||
|
|
|||
|
# Impureté
|
|||
|
#=========================================
|
|||
|
|
|||
|
|
|||
|
# La répétabilité des constructions étant critique pour le
|
|||
|
# gestionnaire de paquets Nix, la pureté fonctionnelle est
|
|||
|
# mise en avant dans le langage Nix. Cependant, il existe des
|
|||
|
# impuretés.
|
|||
|
|
|||
|
# Vous pouvez vous référer aux variables d'environnement.
|
|||
|
(getEnv "HOME")
|
|||
|
#=> "/home/alice"
|
|||
|
|
|||
|
|
|||
|
# La fonction `trace` est utilisée pour le débogage.
|
|||
|
# Elle affiche le premier argument dans `stderr` et
|
|||
|
# évalue le second argument.
|
|||
|
(trace 1 2)
|
|||
|
#=> trace: 1
|
|||
|
#=> 2
|
|||
|
|
|||
|
# Vous pouvez écrire des fichiers dans le magasin Nix (Nix store).
|
|||
|
# Bien qu'impur, c'est assez sûr car le nom du fichier est dérivé
|
|||
|
# du hachage de son contenu. On peut lire des fichiers depuis n'importe où.
|
|||
|
# Dans cet exemple, on écrit un fichier dans le magasin, puis on le relit.
|
|||
|
(let filename = toFile "foo.txt" "hello!"; in
|
|||
|
[filename (builtins.readFile filename)])
|
|||
|
#=> [ "/nix/store/ayh05aay2anx135prqp0cy34h891247x-foo.txt" "hello!" ]
|
|||
|
|
|||
|
# Il est également possible de télécharger des fichiers dans le magasin Nix.
|
|||
|
(fetchurl "https://example.com/package-1.2.3.tgz")
|
|||
|
#=> "/nix/store/2drvlh8r57f19s9il42zg89rdr33m2rm-package-1.2.3.tgz"
|
|||
|
|
|||
|
]
|
|||
|
```
|
|||
|
|
|||
|
### Pour en savoir plus (anglais)
|
|||
|
|
|||
|
- [Nix Manual - Nix expression language](https://nixos.org/nix/manual/#ch-expression-language)
|
|||
|
- [James Fisher - Nix by example - Part 1: The Nix expression language](https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55)
|
|||
|
- [Susan Potter - Nix Cookbook - Nix By Example](https://ops.functionalalgebra.com/nix-by-example/)
|
|||
|
- [Rommel Martinez - A Gentle Introduction to the Nix Family](https://web.archive.org/web/20210121042658/https://ebzzry.io/en/nix/#nix)
|