Browse Source

[notes] import julia (macros)

Gaspard Jankowiak 3 years ago
parent
commit
5968e5fadf
1 changed files with 82 additions and 0 deletions
  1. 82
    0
      notes/julia/index.markdown

+ 82
- 0
notes/julia/index.markdown View File

@@ -0,0 +1,82 @@
1
+---
2
+layout: default
3
+math: true
4
+---
5
+
6
+# Macros
7
+
8
+En Julia, il est possible de définir des expressions ("quoted expressions") qui sont analysées syntaxiquement ("parsées"),
9
+mais pas évaluées, ce qui est assez pratique pour réutiliser un bout de code régulièrement. Par exemple, on peut a souvent
10
+besoin d'échanger le contenu de deux variables, ce qui peut se faire sans variables intermédiaires avec un ou exclusif\* :
11
+
12
+    swap = :(
13
+        x = x ^ y
14
+        y = y ^ x
15
+        x = x ^ y
16
+    )
17
+
18
+\* c'est une [mauvaise idée](https://en.wikipedia.org/wiki/XOR_swap_algorithm#Reasons_for_avoidance_in_practice) en pratique.
19
+
20
+On peut alors insérer `eval(swap)` dans notre code pour échanger le contenu de `x` et `y`,
21
+pour calculer la distance entre `x` et `y` de manière totalement inéfficace, par exemple :
22
+
23
+
24
+    function distance(x, y)
25
+        if x < y
26
+            eval(swap)
27
+        end
28
+        return x - y
29
+    end
30
+
31
+
32
+Pas très pratique, puis qu'on ne peut faire ça que si les variables qui nous intéressent
33
+sont `x` et `y`. Pour plus de flexibilité, on peut définir une macro, sorte d'expression "quotée"
34
+paramétrée. Pour assigner à un vecteur les coordonnées du k-ième vecteur de la base canonique, ça
35
+donnerait :
36
+
37
+    macro set_canonical(vector, k)
38
+        :( fill!($vector, 0); $vector[$k] = 1 )
39
+    end
40
+
41
+On peut alors faire quelque chose comme
42
+
43
+    vector = ones(4)/2;
44
+    @set_canonical(vector, 3)
45
+    vector
46
+    # 4-element Array{Float64,1}:
47
+    #  0.0
48
+    #  0.0
49
+    #  1.0
50
+    #  0.0
51
+
52
+Les différences avec une fonction :
53
+- le code est remplacé à la compilation, il n'y a pas d'appel.
54
+- le code d'une macro est collé tel quel à l'endroit où elle est utilisée, elle peut faire référence à des variables du contexte parent.
55
+
56
+À la différence d'`eval`, une macro est substituée à la compilation.
57
+
58
+## Portée des variables et modules
59
+
60
+Comme une fonction, une macro peut-être définie dans un module.
61
+
62
+    # algebre.jl
63
+    module algebre
64
+    macro set_canonical(vector, k)
65
+        :( fill!($vector, 0); $vector[$k] = 1 )
66
+    end
67
+    end
68
+
69
+Mais il faut alors faire attention :
70
+
71
+    import algebre.jl
72
+
73
+    vector = zeros(4)
74
+    @algebre.set_canonical(vector, 3)
75
+
76
+    # ERROR: LoadError: UndefVarError: vector not defined
77
+
78
+Les variables évaluées dans la macro sont évaluées dans le contexte du module, pas celui où la macro est utilisée. C'est plus compliqué d'une simple copie de code. Comme `vector` n'existe pas dans le contexte du module, d'où l'erreur. Pour palier à ça, on peut utiliser `esc`, qui permet d'accéder au contexte parent depuis un module.
79
+
80
+    macro set_canonical(vector, k)
81
+        esc(:( fill!($vector, 0); $vector[$k] = 1 ))
82
+    end

Loading…
Cancel
Save