89 research outputs found
Adding hygiene to gambit scheme
Le langage de programmation Scheme est reconnu pour son puissant
système de macro-transformations. La représentation
du code source d'un programme, sous forme de données manipulables
par le langage,
permet aux programmeurs de modifier directement
l'arbre de syntaxe abstraite sous-jacent.
Les macro-transformations
utilisent une syntaxe similaire aux procédures régulières mais,
elles définissent plutôt des procédures à exécuter
lors de la phase de compilation.
Ces procédures retournent une représentation sous
forme d'arbre de syntaxe abstraite qui devra être substitué
à l'emplacement de l'appel du transformateur. Les procédures
exécutées durant la phase de compilation profitent
de la même puissance que celles exécutées durant de la phase d'évaluation.
Avec ce genre de système de macro-transformations,
un programmeur peut créer des règles de syntaxe spécialisées
sans aucun coût additionnel en performance:
ces extensions syntactiques
permettent l'abstraction de code sans les coûts d'exécution
habituels reliés à la création d'une fermeture sur le tas.
Cette représentation pour le code source de Scheme provient
directement du langage de programmation Lisp. Le code source
est représenté sous forme de listes manipulables
de symboles, ou bien de
listes contenants d'autres listes: une structure appelée
S-expression. Cependant, avec cette approche simpliste,
des conflits de noms peuvent apparaître.
En effet, l'association référée par un certain identifiant
est déterminée exclusivement par
le contexte lexical de celui-ci.
En déplaçant un identifiant dans l'arbre de syntaxe abstraite,
il est possible que cet identifiant se retrouve dans
un contexte lexical contenant une certaine association pour un identifiant du mĂŞme nom.
Dans de tels cas,
l'identifiant déplacé pourrait ne plus référer à l'association
attendue, puisque cette seconde
association pourrait avoir prévalence sur
la première. L'assurance de transparence référentielle est alors perdue.
En conséquence, le choix de nom pour les identifiants
vient maintenant influencer directement
le comportement du programme,
générant des erreurs difficiles à comprendre.
Les conflits de noms
peuvent être corrigés manuellement dans le code en utilisant,
par exemple, des noms d'identifiants uniques.
La préservation automatique de la transparence référentielle
se nomme hygiène, une notion qui a été beaucoup
étudiée dans le contexte
des langages de la famille Lisp.
La dernière version du Scheme revised report, utilisée
comme spécification pour le langage, étend ce dernier
avec un support pour les macro-transformations hygiéniques.
Jusqu'Ă maintenant,
l'implémentation Gambit de Scheme ne fournissait
pas de tel système à sa base. Comme contribution, nous
avons ré-implémenter le système de macro de Gambit pour
supporter les macro-transformations hygiéniques au plus bas niveau
de l'implémentation. L'algorithme choisi se base sur l'algorithme
set of scopes implémenté dans le langage Racket et créé par Matthew Flatt.
Le langage Racket s'est grandement inspiré
du langage Scheme mais, diverge
sur plusieurs fonctionnalités importantes. L'une de
ces différences est le puissant système de macro-transformation
sur lequel Racket base la majorité de ses primitives.
Dans ce contexte, l'algorithme a donc été testé
de façon robuste.
Dans cette thèse, nous donnerons un aperçu du langage
Scheme et de sa syntaxe. Nous énoncerons le problème d'hygiène
et décrirons différentes stratégies utilisées
pour le résoudre. Nous justifierons par la suite
notre choix d'algorithme et fourniront une définition
formelle. Finalement, nous présenterons une analyse
de la validité et de la performance du compilateur en
comparant la version originale de Gambit avec notre
version supportant l'hygiène.The Scheme programming language is known for
its powerful macro system.
With Scheme source code represented as actual Scheme data,
macro transformations
allow the programmer, using that data, to act directly on the
underlying abstract syntax tree.
Macro transformations use a similar syntax to
regular procedures but, they define procedures
meant to be executed at compile time.
Those procedures return an abstract syntax tree representation
to be substituted at the transformer's call location.
Procedures executed at compile-time use the same
language power as run-time procedures.
With the macro system,
the programmer can create specialized
syntax rules without additional performance costs.
This also allows for code abstractions
without the expected run-time cost of closure creations.
Scheme's representation of source code using values
inherits that virtue from the Lisp programming language.
Source code is represented as a list of symbols, or lists
of other lists: a structure coined S-expressions.
However, with this simplistic approach,
accidental name clashes can occur.
The binding to which an identifier refers to
is determined by the lexical context of that identifier.
By moving an identifier around in the abstract syntax tree,
it can be caught within the lexical context of another binding definition with the same name.
This can cause unexpected behavior for programmers
as the choice of names can create substantial changes
in the program.
Accidental name clashes can be manually fixed in the code,
using name obfuscation, for instance.
However, the programmer becomes responsible
for the program's safety.
The automatic preservation of referential transparency
is called hygiene and was
thoroughly studied in the context
of lambda calculus and Lisp-like languages.
The latest Scheme revised report, used as a specification for the
language, extend the language with hygienic macro
transformations.
Up to this point, the Gambit Scheme implementation
wasn't providing a built-in hygienic macro system.
As a contribution, we re-implemented Gambit's
macro system to support hygienic transformations
at its core.
The algorithm we chose is
based on the set of scopes algorithm, implemented in the
Racket language by Matthew Flatt.
The Racket language is heavily based on Scheme but,
diverges on some core features.
One key aspect of the Racket language is
its extensive hygienic syntactic macro system, on
which most core features are built on:
the algorithm
was robustly tested in that context.
In this thesis, we will give an overview of the Scheme language
and its syntax. We will state the hygiene problem and describe
different strategies used to enforce hygiene automatically.
Our algorithmic
choice is then justified and formalized. Finally, we
present the original Gambit macro system and explain
the changes required. We also provide a validity and performance
analysis, comparing the original Gambit implementation to
our new system
Développement d’un serveur LSP pour Typer
Programmer en un langage de programmation peut être une tâche ardue. Même les plus
chevronnés ne sont pas à l’abri de commettre des erreurs. Il est donc important pour les
programmeurs d’avoir des aides pour écrire leur code plus efficacement et plus rapidement.
Typer est un jeune langage de programmation en développement. Actuellement, le langage a
beaucoup de limitations d’aides pour les programmeurs. En effet, on ne peut coder en Typer
que dans un terminal, dans un fichier et compiler le fichier ou dans des environnements
primitifs. On apporte une solution à ce problème en offrant, dans ce travail, un serveur LSP
au langage qui va offrir des fonctionnalités comme la complétion de code, le surlignement
des erreurs, etc, pour permettre aux programmeurs Typer de coder plus facilement et de
pouvoir le faire dans leur éditeur/IDE préféré.Programming in a programming language can be a daunting task. Even the most seasoned
are not immune to make mistakes. It is therefore important for programmers to have helpers
to write their code more efficiently and quickly. Typer is a young programming language
in development. Currently, the language has a lot of helper limitations for programmers.
Indeed, we can code in Typer only in a terminal, in a file and compile the file or in primitive
environments. We solve this problem by offering in this work, an LSP server to the language
which will offer features such as code completion, error highlighting...etc, to allow Typer
programmers to code more easily and efficiently, and also, to be able to do it in their favorite
editor/IDE
Reusable semantics for implementation of Python optimizing compilers
Le langage de programmation Python est aujourd'hui parmi les plus populaires au monde grâce à son accessibilité ainsi que l'existence d'un grand nombre de librairies standards. Paradoxalement, Python est également reconnu pour ses performances médiocres lors de l'exécution de nombreuses tâches. Ainsi, l'écriture d’implémentations efficaces du langage est nécessaire. Elle est toutefois freinée par la sémantique complexe de Python, ainsi que par l’absence de sémantique formelle officielle.
Pour régler ce problème, nous présentons une sémantique formelle pour Python axée sur l’implémentation de compilateurs optimisants. Cette sémantique est écrite de manière à pouvoir être intégrée et analysée aisément par des compilateurs déjà existants.
Nous introduisons également semPy, un évaluateur partiel de notre sémantique formelle. Celui-ci permet d'identifier et de retirer automatiquement certaines opérations redondantes dans la sémantique de Python. Ce faisant, semPy génère une sémantique naturellement plus performante lorsqu'exécutée.
Nous terminons en présentant Zipi, un compilateur optimisant pour le langage Python développé avec l'assistance de semPy. Sur certaines tâches, Zipi offre des performances compétitionnant avec celle de PyPy, un compilateur Python reconnu pour ses bonnes performances. Ces résultats ouvrent la porte à des optimisations basées sur une évaluation partielle générant une implémentation spécialisée pour les cas d'usage fréquent du langage.Python is among the most popular programming language in the world due to its accessibility and extensive standard library. Paradoxically, Python is also known for its poor performance on many tasks. Hence, more efficient implementations of the language are required. The development of such optimized implementations is nevertheless hampered by the complex semantics of Python and the lack of an official formal semantics. We address this issue by presenting a formal semantics for Python focussed on the development of optimizing compilers. This semantics is written as to be easily reusable by existing compilers. We also introduce semPy, a partial evaluator of our formal semantics. This tool allows to automatically target and remove redundant operations from the semantics of Python. As such, semPy generates a semantics which naturally executes more efficiently. Finally, we present Zipi, a Python optimizing compiler developped with the aid of semPy. On some tasks, Zipi displays performance competing with those of PyPy, a Python compiler known for its good performance. These results open the door to optimizations based on a partial evaluation technique which generates specialized implementations for frequent use cases
Typer a de la classe : le polymorphisme ad hoc dans un langage avec des types dépendants et de la métaprogrammation
La modularité est un enjeu important en programmation, surtout quand on l’enrichit avec des preuves, comme dans les langages avec des types dépendants. Typer est un tel langage, et afin d’augmenter sa modularité et de lui ajouter un moyen de faire la surcharge d’opérateurs, on s’inspire d’Agda et Coq et on l’étend avec les arguments instances, qui généralisent les classes de types de Haskell. Un aspect qui distingue notre conception est que comme Typer généralise les définitions, la généralisation des contraintes de classe est grandement facilitée. Pour pouvoir faire les preuves de lois de classes, on doit également ajouter l’élimination dépendante des types inductifs au langage, dont certains aspects sont en retour facilités par les arguments instances. Sur la base de ces deux fonctionnalités, on offre également une solution au problème de la cécité booléenne, tel que décrit par Harper.Modularity is an important concern for software development, especially when the latter is enriched with proofs in a language with dependent types. Typer is such a language, and in order to increase its modularity, and also provide a way to overload operators, we take inspiration from Agda and Coq and extend it with instance arguments, a generalization of Haskell’s type classes. An aspect that sets our design apart is that since Typer generalizes definitions, it greatly simplifies the generalization of class constraints. In order to allow writing proofs for class laws, we must also implement the dependent elimination of inductive types. In return, instance arguments facilitate some details of dependent elimination. Using both features, we suggest a solution to the problem of Boolean Blindness
Computation over partial information : a principled approach to accurate partial evaluation
On est habitué à penser comme suit à un programme qui exécute: une donnée entre (un input), un moment passe, et un résultat ressort. On assume tacitement de l'information complète sur le input, le résultat, et n'importe quels résultats intermédiaires.
Dans ce travail-ci, on demande ce que ça voudrait dire d'exécuter un programme sur de l'information partielle. Comme réponse possible, on introduit l'interprétation partielle, notre contribution principale. Au lieu de considérer un seul input, on considère un ensemble de inputs possibles. Au lieu de calculer un seul résultat, on calcule un ensemble de résultats possibles, et des ensembles de résultats intermédiaires possibles.
On approche l'interprétation partielle à partir du problème de la spécialisation de programme: l'optimisation d'un programme pour certains inputs. Faire ça automatiquement porte historiquement le nom d'évaluation partielle. Ç'a été appliqué avec succès à plusieurs problèmes spécifiques. On croit que ça devrait être un outil de programmation commun, pour spécialiser des librairies générales pour usage spécifique - mais ce n'est pas le cas.
Souvent, une implantation donnée de l'évaluation partielle ne fonctionne pas uniformément bien sur tous les programmes. Ça se prête mal à un usage commun. On voit ce manque de régularité comme un problème de précision: si l'évaluateur partiel était très précis, il trouverait la bonne spécialisation, indépendamment de notre style de programme.
On propose donc une approche de principe à l'évaluation partielle, visant la précision complète, retirée d'exemples particuliers. On reformule l'évaluation partielle pour la baser sur l'interprétation partielle: le calcul sur de l'information partielle. Si on peut déterminer ce qu'on sait sur chaque donnée dans le programme, on peut décider quelles opérations peuvent être éliminées pour spécialiser le programme: les opérations dont le résultat est unique.
On définit une représentation d'ensembles qui ressemble à la définition en compréhension, en mathématiques. On modifie un interpréteur pour des programmes fonctionnels, pour qu'il calcule sur ces ensembles. On utilise un solver SMT pour réaliser les opérations sur les ensembles. Pour assurer la terminaison de l'interpréteur modifié, on applique des idées de l'interprétation abstraite: le calcul de point fixe, et le widening. Notre implantation initiale produit de bons résultats, mais elle est lente pour de plus gros exemples. On montre comment l'accélérer mille fois, en dépendant moins de SMT.We are used to the following picture of an executing program: an input is provided, the program runs for a while, and a result comes out. We tacitly assume complete information about the input, the result, and any intermediate results in between.
In this work, we ask what it would mean to execute a program over partial information. As a possible answer, we introduce partial interpretation, our main contribution. Instead of considering a unique input, we consider a set of possible inputs. Instead of computing a unique result, we compute a set of possible results, and sets of possible intermediate results.
We approach partial interpretation from the problem of program specialization: the optimization of a program's execution time for certain inputs. Doing this automatically is historically known as partial evaluation. Partial evaluation has been applied successfully to many specific problems. We believe it should be a mainstream programming tool, to specialize general libraries for specific use - but such a tool has not been delivered.
One common problem is that a given implementation of partial evaluation is inconsistent: it does not work uniformly well on all input programs. This inconsistency makes it unsuited for mainstream use. We view this inconsistency as an accuracy problem: if the partial evaluator was very accurate, it would find the correct specialization, no matter how we present the input program.
We therefore propose a principled approach to partial evaluation, aimed at complete accuracy, removed from any particular example program. We reformulate partial evaluation to root it in partial interpretation: computation over partial information. If we can determine what we know about every piece of data in the program, we can decide which operations can be removed to specialize the program: those operations whose result is uniquely known.
We represent sets with a kind of mathematical set comprehension. We modify an interpreter for functional programs, to compute over these sets. We use an SMT solver (Satisfiability Modulo Theories) to perform set operations. To ensure termination of the modified interpreter, we apply ideas from abstract interpretation: fixed point computation, and widening. Our initial implementation produces good results, but it is slow for larger examples. We show how to speed it up a thousandfold, by relying less on SMT
Diffusion de modules compilés pour le langage distribué Termite Scheme
Ce mémoire décrit et évalue un système de module qui améliore la migration de code dans le
langage de programmation distribuée Termite Scheme. Ce système de module a la possibilité
d’être utilisé dans les applications qu’elles soient distribuées ou pas. Il a pour but de faciliter
la conception des programmes dans une structure modulaire et faciliter la migration de code
entre les nœuds d’un système distribué. Le système de module est conçu pour le système
Gambit Scheme, un compilateur et interprète du langage Scheme utilisé pour implanter
Termite. Le système Termite Scheme est utilisé pour implémenter les systèmes distribués.
Le problème qui est résolu est la diffusion de code compilé entre les nœuds d’un système
distribué quand le nœud destination n’a aucune connaissance préalable du code qu’il reçoit.
Ce problème est difficile car les nœuds sont hétérogènes, ils ont différentes architectures (x86,
ARM).
Notre approche permet d’identifier les modules de façon unique dans un contexte dis-
tribué. La facilité d’utilisation et la portabilité ont été des facteurs importants dans la
conception du système de module.
Le mémoire décrit la structure des modules, leur implémentation dans Gambit et leur
application. Les qualités du système de module sont démontrées par des exemples et la
performance est évaluée expérimentallement.This thesis presents a module system for Termite Scheme that supports distributed computing.
This module system facilitates application modularity and eases code migration
between the nodes of a distributed system. This module system also works for developing
non-distributed applications. The Gambit Scheme system is used to implement the
distributed Termite and the Module system.
The problem that is solved is the migration of compiled code between nodes of a distributed
system when the receiving node has no prior knowledge of the code. This is a
challenging problem because the nodes are not homogenous, they have different architectures
(ARM, x86).
Our approach uses a naming model for the modules that uniquely identifies them in a
distributed context. Both ease of use and portability were important factors in the design
of the module system.
The thesis describes a module system and how it was integrated into Gambit. The
system allows developing distributed modular systems. The features of this system are
shown through application examples and the performance is evaluated experimentally
Introducing Computational Thinking in K-12 Education: Historical, Epistemological, Pedagogical, Cognitive, and Affective Aspects
Introduction of scientific and cultural aspects of Computer Science (CS) (called "Computational Thinking" - CT) in K-12 education is fundamental. We focus on three crucial areas.
1. Historical, philosophical, and pedagogical aspects. What are the big ideas of CS we must teach? What are the historical and pedagogical contexts in which CT emerged, and why are relevant? What is the relationship between learning theories (e.g., constructivism) and teaching approaches (e.g., plugged and unplugged)?
2. Cognitive aspects. What is the sentiment of generalist teachers not trained to teach CS? What misconceptions do they hold about concepts like CT and "coding"?
3. Affective and motivational aspects. What is the impact of personal beliefs about intelligence (mindset) and about CS ability? What the role of teaching approaches?
This research has been conducted both through historical and philosophical argumentation, and through quantitative and qualitative studies (both on nationwide samples and small significant ones), in particular through the lens of (often exaggerated) claims about transfer from CS to other skills.
Four important claims are substantiated.
1. CS should be introduced in K-12 as a tool to understand and act in our digital world, and to use the power of computation for meaningful learning. CT is the conceptual sediment of that learning. We designed a curriculum proposal in this direction.
2. The expressions CT (useful to distantiate from digital literacy) and "coding" can cause misconceptions among teachers, who focus mainly on transfer to general thinking skills. Both disciplinary and pedagogical teacher training is hence needed.
3. Some plugged and unplugged teaching tools have intrinsic constructivist characteristics that can facilitate CS learning, as shown with proposed activities.
4. Growth mindset is not automatically fostered by CS, while not studying CS can foster fixed beliefs. Growth mindset can be fostered by creative computing, leveraging on its constructivist aspects
From Macros to DSLs: The Evolution of Racket
The Racket language promotes a language-oriented style of programming. Developers create many domain-specific languages, write programs in them, and compose these programs via Racket code. This style of programming can work only if creating and composing little languages is simple and effective. While Racket\u27s Lisp heritage might suggest that macros suffice, its design team discovered significant shortcomings and had to improve them in many ways. This paper presents the evolution of Racket\u27s macro system, including a false start, and assesses its current state
- …