XMonad

Étant utilisateur de GNU/Linux depuis quelques années maintenant, j’ai eu l’occasion de tester quelques distributions et quelques environnements de bureau. Parmi les distributions je suis passé par Ubuntu, Debian, Fedora pour enfin essayer Archlinux, que je n’ai plus quitté depuis. En terme d’environnement c’est un peu la même chose, gnome, xfce, lxde, openbox puis Awesome que j’ai utilisé pendant une année. Je n’ai jamais trop cherché à modifier la configuration par défaut, qui me convenait plutôt bien. Puis je me suis mis au Haskell, et avec lui des envies de refaire le monde, des envies de pureté, des envies de paresse (enfin pas tant que ça !), et j’ai ouï dire qu’il existait un gestionnaire de fenêtre écrit avec ce fabuleux langage : XMonad !

Présentation de XMonad

XMonad est un gestionnaire de fenêtre de style « tiling » (c’est à dire qu’il est capable de gérer tout seul la disposition des fenêtres afin d’optimiser l’espace). Il est léger, épuré, très minimaliste. En fait la première fois qu’on le lance il n’y a rien, à part un curseur de souri ! C’est un bon début. A la différence d’Awesome qui propose tout de même un minimum syndical (une barre de tâches, une vue des différents tags, l’heure…). Sur XMonad rien de tout ça. J’ai vraiment eu l’impression qu’on me fournissait des briques de base, et qu’ensuite c’était à moi de jouer pour me construire mon propre gestionnaire de fenêtre, et c’est en quelque sorte ce que j’ai fait. Heureusement les ressources se trouvent assez facilement sur internet, à partir de la documentation, d’articles et d’exemples, on parvient à créer un petit environnement douillet en quelques heures (à condition de connaitre quelques bribes de Haskell, car oui, XMonad se configure en Haskell !). Au final, il n’y a pas à dire, c’est un gestionnaire de fenêtre fonctionnel.

Installation

Pour les utilisateur de Archlinux il suffit d’exécuter la commande suivante ! Pour les autres, une petit tour par la documentation de votre distribution favorite devrait
vous éguiller.

1
pacman -S xmonad xmonad-contrib

Configuration

Venons-en au sujet qui fâchent, à savoir, la configuration. Comme dit un peu plus haut, ça se fait en utilisant le langage Haskell et on place tout ça dans un fichier nommé xmonad.hs dans un dossier ~/.xmonad. Puisque c’est du Haskell, vous l’aurez deviné, ça se compile. Heureusement cela se fait à chaud, sans avoir besoin de quitter XMonad, ce qui est très appréciable. Grâce au raccourci Mod + q le fichier de configuration est recompilé, si il est correct il est appliqué à chaud, sinon une fenêtre s’ouvre vous indiquant les éventuelles erreurs, et l’ancienne configuration est conservée. Comme ça, pas de risque de casser votre environnement en le modifiant en cours d’utilisation.

Je vais vous présenter ma configuration actuelle, qui est assez basique, mais comble amplement mes attentes. Ensuite je vais détailler quelques points importants.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
{- Config of berson_r -}

import System.Exit
import System.IO
import XMonad
import XMonad.Actions.CycleWS
import XMonad.Actions.GridSelect
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Layout.Fullscreen
import XMonad.Layout.NoBorders
import XMonad.Layout.Spiral
import XMonad.Layout.Tabbed
import XMonad.Util.EZConfig(additionalKeys)
import XMonad.Util.Run(spawnPipe)
import qualified Data.Map        as M
import qualified XMonad.StackSet as W


-- Main
main = do
    xmproc <- spawnPipe "xmobar /home/berson_r/.xmobarrc" -- lance xmobar avec le bon fichier de config
    spawn "nitrogen --restore" -- affiche le fond d'écran
    xmonad $ defaultConfig { -- redéfinition de certaines options de XMonad
    -- simple stuff
    terminal           = myTerminal,
    modMask            = myModMask,
    workspaces         = myWorkspaces,
    normalBorderColor  = myNormalBorderColor,
    focusedBorderColor = myFocusedBorderColor,

    -- key bindings
    keys               = myKeys,
    -- mouseBindings      = myMouseBindings,

    -- hooks, layouts
    layoutHook         = smartBorders $ myLayout,
    manageHook         = myManageHook,
    logHook            = myLogHook xmproc,
    startupHook        = myStartupHook
    }


-- Binding for the mod key
myModMask :: KeyMask
myModMask = mod4Mask

-- Default terminal to use
myTerminal :: String
myTerminal = "urxvt"

-- Names of the workspaces
myWorkspaces :: [String]
myWorkspaces = ["term", "web", "mail", "music"] ++ (map show [5..9])

-- Color of normal borders
myNormalBorderColor :: String
myNormalBorderColor  = "#7c7c7c"

-- Color of the selected window's borders
myFocusedBorderColor :: String
myFocusedBorderColor = "#ffb6b0"

-- Color of current window title in xmobar.
xmobarTitleColor :: String
xmobarTitleColor = "#FFB6B0"

-- -- Color of current workspace in xmobar.
xmobarCurrentWorkspaceColor :: String
xmobarCurrentWorkspaceColor = "#CEFFAC"

-- Custom layout
myLayout = avoidStruts (
    Tall 1 (3/100) (1/2) |||
    Mirror (Tall 1 (3/100) (1/2)) |||
    tabbed shrinkText tabConfig |||
    Full |||
    spiral (6/7)) |||
    noBorders (fullscreenFull Full)

-- Colors for text and backgrounds of each tab when in "Tabbed" layout.
tabConfig = defaultTheme {
    activeBorderColor = "#7C7C7C",
    activeTextColor = "#CEFFAC",
    activeColor = "#000000",
    inactiveBorderColor = "#7C7C7C",
    inactiveTextColor = "#EEEEEE",
    inactiveColor = "#000000"
}


myStartupHook = return ()

-- Custom rules
myManageHook :: ManageHook
myManageHook = composeAll
    [ className =? "Chromium"       --> doShift "web"
    , className =? "Firefox"        --> doShift "web"
    , className =? "Uzbl-core"      --> doShift "web"
    , className =? "Thunderbird"    --> doShift "mail"
    , className =? "Spotify"        --> doShift "music"
    , className =? "Vlc"            --> doFloat
    , className =? "Steam"          --> doFloat
    , className =? "Gimp"           --> doFloat
    , manageDocks]
--    , isFullscreen --> (doF W.focusDown <+> doFullFloat)]

myLogHook :: Handle -> X ()
myLogHook xmproc = dynamicLogWithPP xmobarPP {
    ppOutput = hPutStrLn xmproc,
    ppTitle = xmobarColor "green" "" . shorten 50
}


-- Key bindings --
myKeys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $

  -- Custom key bindings

  [ ((modMask .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf) -- start term
  , ((modMask, xK_r), spawn "exe=`dmenu_path_c | yeganesh` && eval \"exec $exe\"") -- dmenu
  , ((modMask .|. controlMask, xK_m), spawn "amixer -q set Master toggle") -- mute volume
  , ((modMask .|. controlMask, xK_j), spawn "amixer -q set Master 10%-") -- dec volume
  , ((modMask .|. controlMask, xK_k), spawn "amixer -q set Master 10%+") -- inc volume
  , ((modMask, xK_g), goToSelected defaultGSConfig) -- display selection grid
  -- workspaces
  , ((modMask, xK_Right), nextWS)
  , ((modMask .|. shiftMask, xK_Right), shiftToNext)
  , ((modMask, xK_Left), prevWS)
  , ((modMask .|. shiftMask, xK_Left), shiftToPrev)

  -- "Standard" xmonad key bindings

  , ((modMask .|. shiftMask, xK_c), kill) -- close selected window
  , ((modMask, xK_space), sendMessage NextLayout) -- change layout
  , ((modMask .|. shiftMask, xK_space), setLayout $ XMonad.layoutHook conf) -- reset layout
  , ((modMask, xK_n), refresh) -- resize windows to the correct size
  , ((modMask, xK_Tab), windows W.focusDown) -- move focus to next window
  , ((modMask, xK_j),   windows W.focusDown) -- move focus to next window
  , ((modMask, xK_k),   windows W.focusUp)   -- move focus to previous window
  , ((modMask, xK_m),   windows W.focusMaster) -- move focus to master window
  , ((modMask, xK_Return), windows W.swapMaster) -- swap focused and master window
  , ((modMask .|. shiftMask, xK_j), windows W.swapDown) -- swap focused and next window
  , ((modMask .|. shiftMask, xK_k), windows W.swapUp) -- swap focused and previous window

  -- Shrink the master area.
  , ((modMask, xK_h),
     sendMessage Shrink)

  -- Expand the master area.
  , ((modMask, xK_l),
     sendMessage Expand)

  -- Push window back into tiling.
  , ((modMask, xK_t),
     withFocused $ windows . W.sink)

  -- Increment the number of windows in the master area.
  , ((modMask, xK_comma),
     sendMessage (IncMasterN 1))

  -- Decrement the number of windows in the master area.
  , ((modMask, xK_period),
     sendMessage (IncMasterN (-1)))

  -- Toggle the status bar gap.
  -- TODO: update this binding with avoidStruts, ((modMask, xK_b),

  -- Quit xmonad.
  , ((modMask .|. shiftMask, xK_q),
     io (exitWith ExitSuccess))

  -- Restart xmonad.
  , ((modMask, xK_q),
     restart "xmonad" True)
  ]
  ++
 
  -- mod-[1..9], Switch to workspace N
  -- mod-shift-[1..9], Move client to workspace N
  [((m .|. modMask, k), windows $ f i)
      | (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9]
      , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
  ++

  -- mod-{w,e,r}, Switch to physical/Xinerama screens 1, 2, or 3
  -- mod-shift-{w,e,r}, Move client to screen 1, 2, or 3
  [((m .|. modMask, key), screenWorkspace sc >>= flip whenJust (windows . f))
      | (key, sc) <- zip [xK_w, xK_e, xK_p] [0..]
      , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]

Globalement, on peut résumer l’organisation du fichier de configuration comme ceci :

  1. Les imports permettant de faire appel à des fonctionnalités de XMonad, ou toute autre bibliothèque Haskell (car vous pouvez vraiment mettre n’importe quoi dans votre fichier de configuration, si vous le vouliez vous pourriez coder factorielle, Fibonacci et un crible d’Ératosthène pour les afficher dans votre barre des tâches, aucun problème !).
  2. Des redéfinitions d’options ou de comportements sous forme de constantes.
  3. Une fonction Main qui regroupe tout ceci et spécifie à XMonad toutes les options, et les comportements que vous désirez. Globalement vous pourrez quasiment tout modifier via un type enregistrement. Les champs non spécifiés auront leur valeur par défaut, on se contente donc de spécifier ce qui nous intéresse.

Barre d’état

Par défaut, XMonad ne dispose pas d’une barre des tâches. Il en existe une qui est également en Haskell et qui s’intègre très simplement avec XMonad, il s’agit de XMobar. Elle est très légère et permettra de répondre à la plupart des besoins. Il suffit pour la mettre en place de :

  1. Disposer d’un fichier de configuration situé ici : ~/.xmobarrc (vous trouverez le mien un peu plus bas)
  2. Rajouter la ligne : xmproc <- spawnPipe "xmobar /home/berson_r/.xmobarrc" en haut de votre fonction main (cf mon fichier de configuration ci-dessus).
  3. Indiquer quelles informations XMonad doit transmettre à XMobar lors de l’exécution (les workspaces par exemple). Pour ceci il faut redéfinir le myLogHook dans le main, je vous invite encore une fois à regarder mon exemple donné un peu plus haut.
1
2
3
4
5
6
7
8
9
10
11
12
Config { font = "-*-Fixed-Bold-R-Normal-*-13-*-*-*-*-*-*-*"
, bgColor = "black"
, fgColor = "grey"
, position = TopW L 90
, lowerOnStart = True
, commands = [ Run Date "%a %b %_d %H:%M" "date" 10
, Run StdinReader
]
, sepChar = "%"
, alignSep = "}{"
, template = "%StdinReader% }{ <fc=#ee9a00>%date%</fc> =<<"
}

Attention, contrairement aux apparences, ce n’est pas du Haskell, donc ne mettez pas de commentaires dans ce fichier. Une fois les deux étapes décrites plus hauts effectuées, xmobar devrait s’afficher au lancement de XMonad. Vous remarquerez qu’il affiche les workspaces, l’application qui a le focus, l’heure, la date et … c’est tout. En plus il y a un espace de 10% de la taille de l’écran sur la droite. Il servira à mettre un trayer. C’est justement l’objet de la section suivante.

System Tray

Par défaut, ni XMonad ni xmobar ne proposent un « trayer », où vous pourriez voir les icônes des applications en cours d’exécution. Pour cela j’utilise trayer, qui est très léger et facile à mettre en place. En fait, une fois qu’on lui a réservé une petite place (ce qui est notre cas), il suffit de le lancer avec les bonnes options depuis notre .xinitrc (ou .Xsessions). Voici la commande telle que je l’utilise :

1
2
3
trayer --edge top --align right --SetDockType true --SetPartialStrut true --expand true \
--width 10 -heighttype pixel --height 12                                            \
--transparent true --alpha 0 --tint 0x000000 &

 Fond d’écran

Vous l’aurez compris, XMonad ne propose pas non plus par défaut d’utilitaire pour changer l’image ou la couleur du fond d’écran. Mais il est relativement simple d’en mettre un en place. J’ai personnellement utilisé nitrogen. Il est très simple à utiliser, la première fois il suffit de le lancer à la main et d’aller chercher le fond d’écran désiré. Ensuite, il suffira de le relancer à chaque démmarage avec la commande :

1
nitrogen --restore &

Et c’est exactement le rôle de la ligne 23 dans la fonction main du fichier xmonad.hs :

1
spawn "nitrogen --restore"

Raccourcies clavier utiles

Le seul raccourci qu’il me manquait afin que ce soit parfait, était le « mod + flèche » afin de se déplacer sur le workspace de droite ou de gauche. Pour ce faire, il suffit de rajouter les lignes suivantes dans le tableau des raccourcis personnalisés :

1
2
3
4
, ((modMask, xK_Right), nextWS)
, ((modMask .|. shiftMask, xK_Right), shiftToNext)
, ((modMask, xK_Left), prevWS)
, ((modMask .|. shiftMask, xK_Left), shiftToPrev)

Il y a d’autres options que je n’ai pas détaillées dans cet article, mais j’ai laissé quelques commentaires dans le fichier de configuration afin de guider la compréhension. Si jamais ils ne sont pas suffisents, n’hésitez pas à laisser un commentaire pour poser une question, ou faire une remarque.

Sciences et critique

Une récente réflexion personnelle m’a amené à considérer l’influence de l’étude des sciences (mathématiques, physiques, etc.) sur la capacité à être critique, à faire preuve de discernement dans la vie des tous les jours. Je prendrai ici appui sur l’exemple des mathématiques afin d’étayer mon propos, mais le parallèle avec d’autres sciences est possible.
Je vais donc essayer de présenter quelques traits de caractère, ou habitudes et montrer en quoi ils peuvent être éveillés et entretenus par les sciences, et encourager une vision critique et une prise de recul par rapport aux informations glanées quotidiennement.

Le doute

Il est arrivé dans l’histoire des mathématiques que les mathématiciens, parmi les plus talentueux, en se fiant à leur instinct, à leur intuition, énoncent des vérités erronées. C’est en particulier Bourbaki qui écrivit [1] (peut-être pas en premier) que pour mener un travail rigoureux en mathématiques, il ne fallait pas écouter son intuition, car celle-ci se trouve souvent impuissante face à l’abstraction et l’inconnu, en revanche, il est en général sûr de se fier à des axiomes et des raisonnements logiques rigoureux afin de cheminer dans l’abstrait. Vous vous demandez peut-être le lien entre ce que vous venez de lire et le « doute ». Je pense que pour éviter les pièges, éviter de se tromper en croyant avoir affaire à l’évidence, il faut tout remettre en doute, y compris sa propre intuition. C’est ce que les sciences m’ont appris, et c’est ce que j’ai pris le réflexe de mettre en pratique quotidiennement. Si l’on commence à remettre en doute même ses intuitions, on est capable de tout remettre en doute, y compris les autres. Attention, remettre en doute ne signifie pas rejeter l’autre et son propos, mais juste procéder à une mise à l’épreuve de l’information que l’on reçoit. J’entends trop régulièrement des proches m’énoncer des faits, sortis de nulle part, et qui en cherchant un peu, se révèlent être faux, mais quand on a lu quelque chose, ou si on l’a vu à la télévision, c’est que ça doit être vrai… Il faut chercher l’argumentation, et se ramener à des bases solides, à un raisonnement, à une logique, presqu’à une démonstration, et c’est ce qui m’amène au point suivant, la rigueur.

La rigueur

La rigueur des sciences, la rigueur mathématique, est un allié précieux lorsqu’il s’agit de traquer et de démasquer le faux, déguisé en évidence. La pratique régulière des sciences, en particulier des mathématiques, pousse à cette rigueur, et c’est ce qui est reposant avec elles, c’est qu’une fois un théorème prouvé rigoureusement, il est vrai. Modulo l’erreur inhérente à l’être humain bien sûr. Mais des faits [2] énoncés par des philosophes Grecs il y a plus de deux milles ans n’ont jamais été autant d’actualité, ni autant enseignés dans nos écoles, c’est du solide ! La rigueur, allié au raisonnement, mène à la preuve, à la démonstration, et idéalement, nous devrions avoir ce réflexe d’une analyse rigoureuse des informations qui nous parviennent, et pour cela, les sciences aident.

De même, lorsqu’on a pris l’habitude de raisonner, de chercher la preuve, de chercher l’argument pouvant servir à la démonstration, on est plus enclin à détecter les failles, les erreurs dans les démonstrations ou les argumentations des autres. Parfois, on peut avoir cette intuition que quelque chose cloche (il arrive que les intuitions soient bonnes, d’autres fois non, mais on peut leur laisser leur chance, et les mettre à l’épreuve). Je pense que c’est ce qu’on peut appeler du discernement.

Capacité d’abstraction

Dernier point important, la capacité d’abstraction. Les mathématiques enseignent l’art et la manière d’abstraire les choses. Lorsqu’un problème se présente, le mathématicien exercé aura plus de facilité à le dépouiller de toute information inutile, le changer de contexte, le relier à d’autres faits, le regarder sous un autre angle. Cette capacité à abstraire les choses de leur contexte premier est essentielle, pour détecter des mécanismes cachés, des liens masqués, des structures sous-jacentes, quel que soit le problème considéré. Allié à une ouverture d’esprit et à une vision globale, c’est à dire, parvenir à ne pas rester focaliser sur l’information présente, mais arriver à voir toutes les autres en même temps, prendre le recul nécessaire afin de traiter le problème dans son ensemble, dans sa globalité et non localement, avec une vision partielle du contexte, cette qualité permet également de ne pas considérer qu’une seule version du problème, mais plusieurs. Il est parfois utile de s’ouvrir à toutes les possibilités. Et encore une fois, les sciences sont un excellent terrain de jeu pour s’entrainer !

Contexte

Dans un monde où il serait plus nécessaire que jamais de remettre en doute la véracité de l’information à laquelle on peut accéder, dans une société de l’ouverture, de l’internet et du partage des données, il est vital de développer des outils nous permettant de faire le tri dans les quantités astronomiques d’informations que nous sommes amenés à traiter et assimiler quotidiennement. Le doute, la rigueur, l’abstraction, l’ouverture d’esprit, la curiosité, sont les germes de l’indépendance intellectuelle, qu’il est nécessaire de cultiver continûment. Les sciences, qu’elles soient humaines ou autres (mathématiques, physique, biologie, philosophies, sociologie, géopolitique, etc.) sont plus que jamais nécessaires pour comprendre le monde dans lequel nous vivons.

Références :
[1] Nicolas Bourbaki – Éléments d’histoire des mathématiques
[2] Euclide – Les éléments

 

Gestion et transmission de la connaissance

Récemment sensibilisé à la discipline de la gestion des connaissances (ou Knowledge Management, KM en anglais), j’ai eu l’occasion de réfléchir sur le sujet. En particulier, j’aimerais adresser quelques critiques à la spirale de Nonaka :

The Knowledge Spiral as described by Nonaka & Takeuchi.

Cette spirale décrit une modélisation du cycle classique de la transmission de la connaissance, elle doit être lue comme suit :

  1. Socialization : transmission de connaissances dites implicites par le biais de la discussion avec d’autres personnes ;
  2. Externalization : action d’externaliser ses connaissances sur un support quelconque (feuille de papier par exemple) ;
  3. Combination : processus d’enrichissement des connaissances par agrégation, ajout d’informations à des connaissances déjà externalisées sur un support physique ;
  4. Internalization : phénomène de compréhension et d’assimilation de connaissances depuis un support quelconque.

Schéma de communication des connaissances

Premièrement, la socialization n’est pas considérée comme une externalisation de l’information comme pourrait l’être l’action d’écrire sur une feuille de papier. Deuxièmement, je pense qu’un schéma d’aller-retour pourrait également être adapté pour décrire le cycle de la connaissance. Voici ma vision des choses.

Untitled drawing

En fait, il s’agit ici d’un changement de représentation, tout en gardant les mêmes étapes que celles présentées par la spirale de Nonaka. Je vais donc représenter les différentes étapes de la transmission des connaissances, mais en les interprétant relativement au nouveau schéma.

  1. Socialization : cette étape est absente du nouveau schéma, car je pense qu’elle est complètement identique à l’étape d’Externalization, seul le support change. Puisque la voix est une représentation éphémère de la pensée et ne dispose que d’une portée réduite. Néanmoins, il s’agit tout de même d’une externalisation de la pensée qui permet de la transmettre à autrui.
  2. Composition : cette étape a également disparu du schéma, mais elle peut être recrée en réitérant le schéma plusieurs fois. C’est-à-dire qu’une personne A va transmettre une connaissance à une personne B, cette dernière l’assimile, l’interprète, y ajoute son expérience personnelle, et peut en retour l’échanger à la personne A. Il s’agit donc d’une composition, et ce processus est indépendant du support par lequel l’information transite entre A et B. Ce processus peut impliquer plus que deux personnes.
  3. Externalization : cette étape reste inchangée. Néanmoins, vous aurez remarqué qu’après l’externalisation, ce n’est plus de la connaissance mais de l’information qui transite sur le support, du moins jusqu’à ce que l’interlocuteur l’ai reçue, interprétée et assimilée ; c’est alors que l’information devient connaissance.
  4. Internalization : ce processus permet de transformer l’information en connaissance, par la compréhension, l’interprétation et l’assimilation, la personne s’approprie la connaissance transmise. Je parle d’interprétation, car la compréhension dépend grandement de la manière dont la source de l’information a externalisé son savoir. De même, la spécificité de chaque individu fait que lors de la compréhension, il est probable qu’il y ai interprétation de l’information, dépendant des expériences personnelles, et du savoir du receveur.

Nous avons donc un schéma un peu plus général de transmission, ou plutôt un modèle, une manière de voir les choses. L’intérêt est que ce schéma ne dépend pas du support de transmission de l’information. Pour terminer, j’aimerais vous soumettre quelques remarques :

  • Lors d’une transmission de savoir, après l’externalisation, ce n’est plus de la connaissance qui est sur le support, mais de l’information. Et cette information se transformera en connaissance une fois qu’elle aura été interprétée et comprise par le receveur.
  • Cette information intermédiaire dépend grandement de l’étape d’externalisation. C’est pourquoi, pour faciliter la transmission de connaissances, il faut veiller à améliorer la qualité de l’externalisation (« On sait toujours plus que ce qu’on peut dire »), bien choisir le support, et accompagner la phase d’interprétation de l’interlocuteur.

Cet article est hautement subjectif, et n’engage que moi. Je vous encourage donc à poster des commentaires afin de discuter ou critiquer mon analyse !

[C++] Taille d’un tableau static en temps constant

J’ai découvert cette semaine une petite astuce que je trouve assez élégante, même si son utilité est assez limitée. Il est possible grâce à un template de garder la trace de la taille d’un tableau static entre des appels de fonctions. Voyez plutôt :

template <typename T, int N>
int size(T (&)[N])
{
    return N;
}

int main()
{
    int tab[42];
    cout << size(tab) << endl;
    return 0;
}

Notre fonction size est une fonction template qui prend en paramètre le type T des éléments stockés dans le tableau, ainsi que sa taille. Ainsi lorsqu’on appelle notre fonction size sur un tableau, cette fonction est spécialisée à la compilation avec la bonne valeur de N et le bon type T et chaque appel sera remplacé par la valeur N, qui est la taille du tableau.

Notez également que pour garder l’information de la taille du tableau, il faut passer une référence sur le pointeur du tableau. Si notre fonction size avait simplement pris un pointeur en argument ça n’aurait pas marché puisque le compilateur ne garde pas l’information de la taille, et considère l’argument comme un simple pointeur.

[Ascii] Astuces

Voici quelques petites astuces afin de manipuler plus simplement des caractères encodés en ASCII.

1. Changer la casse

Cette astuce est indiquée dans le page de man(1) ascii, mais je l’ai découverte très récemment car je n’avais pas eu le réflexe de lire les paragraphes se trouvant à la suite de la table ASCII sur cette page de man. Afin de changer la casse d’une lettre (c’est à dire passer de minuscule à majuscule, ou l’inverse), il suffit de changer le 5ième bit. Celui-ci est à 1 pour les minuscules et à 0 pour les majuscules. Donc en effectuant un XOR 32 avec une lettre on change sa casse. C’est tout de même pratique !

2. Manipuler les chiffres

Afin de convertir un entier entre 0 et 9 en son équivalent en caractère ASCII (’0′ à ’9′), on ajoute (ou soustrait selon le sens de la conversion) la valeur de ’0′. On peut aussi remarquer qu’entre un entier et son équivalent en ASCII seuls 2 bits changent. Il s’agit donc de mettre les 6ième et 5ième bits à 1 (ou 0 si on désire passer d’un caractère à un entier). Il suffit donc d’un simple XOR 48, comme ceci :

’9′ XOR 48 = 9

Ces deux astuces sont assez basiques, mais cela peut toujours servir !

[Ocaml] Hashtable Vs Pattern- Matching

Dans le cadre d’un projet personnel j’en suis venu à réaliser un lexer avec l’excellent Ocamllex. Afin de matcher les mots clés du langage source (le langage Python), deux solutions se sont offertes à moi afin d’associer un token à chaque string représentant un mot clé :

  1. Utiliser une Hashtable dans laquelle chaque entrée (clé, valeur) représente un mot clé et son token associé.
  2. Utiliser le pattern matching où chaque entrée correspond à un token.

Les deux solutions ayant une « verbosité » équivalente (j’ai tout de même une légère préférence pour le pattern matching, que je trouve un peu plus lisible), je me suis demandé si les performances étaient équivalentes. J’ai donc réalisé un petit benchmark afin de comparer les deux solutions.

Les deux méthodes ont donc été testées avec une entrée de 3.000.000 de chaines de caractères contenant, à fréquences d’apparition égales, tous les mots clés possibles ainsi que des mots-clés non existants.

Le programme a été compilé sans flag d’optimisation particulier. La machine de test était équipée d’un processeur Atom 1,2 Ghz et 1 Go de mémoire vive. Voici le résultat:

  • Hashtable :  1,259 secondes.
  • Pattern-matching : 2,265 secondes.

Victoire pour les Hashtables. Dommage que le compilateur n’optimise pas le pattern-matching en Hash table lorsque c’est possible.

Visualiser la structure d’un projet python

Lors d’une de mes dernières contributions à un projet écrit en Python, j’ai voulu trouver un moyen de rapidement pouvoir visualiser la structure d’un projet selon plusieurs critères (dépendances entres les modules, héritages entre les objets, etc.). J’ai donc écris un script Python qui permet de générer un graphe à partir de différentes données.

- Projet sur GitHub -

J’ai essayé de faire en sorte de rentre le projet flexible afin de pouvoir scanner d’autres types de données à l’avenir (et pourquoi pas d’autres langages). Pour le moment on peut générer le graphe des importations ainsi que le graphe de l’héritage.

Le projet est divisé en deux parties :

  1. Les fichiers Scan, qui doivent respecter l’interface d’un scanner.
  2. Un objet modelViewer qui s’occupe de parcourir tout votre projet et d’appeler son scanner sur chaque fichier.

Ainsi on peut tout à fait rajouter des Scanners à volonté. Pour finir, voici un graphe de dépendance d’un de mes projets en Python. Le graphe est coloré et chaque module (chaque dossier) possède sa propre couleur.

N’hésitez pas à faire des remarques ou à proposer des améliorations !