Acid, le lisp-like de la communauté !

Créons notre langage de programmation ! Pour le fun !

a marqué ce sujet comme résolu.

Ah oui merde, c'était pas un bon exemple, mais ça évalue à la fois x et x * 5, donc par exemple si j'ai une fonction qui fait des effets secondaires ou bien même une fonction récursive:

1
2
3
4
5
6
(define fact (lambda (n)
  (if (= n 0)
    1
    (* n (fact (- n 1))
  )
))

Ici si on appelle fact on aura toujours une erreur RuntimeError: maximum recursion depth exceeded in comparison.

Ah oui merde, c'était pas un bon exemple, mais ça évalue à la fois x et x * 5, donc par exemple si j'ai une fonction qui fait des effets secondaires ou bien même une fonction récursive

Heu… non. En python ça marche normalement :

1
2
3
>>> fact = lambda n: 1 if n==0 else n*fact(n-1)
>>> fact(10)
3628800

Je ne sais pas ce que tu génère mais normalement le terme n'est pas évalué

Salut,

J'ai réécrit l'exemple de la suite de Fibonacci, voici à quoi ça ressemble:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/*
 * Suite de Fibonacci
 */

// n-ième terme de la suite de Fibonacci
(define fib (lambda (n)
  (# (fibs n) (negate 1))
))

// Suite de Fibonacci jusqu'au n-ième terme
(define fibs (lambda (n)
  (fibHelper n 1 1)
))

(define fibHelper (lambda (i x y)
  (if (== i 0)
    (list)
    (append x (fibHelper (- i 1) y (+ x y)))
  )
))

Comme vous pouvez le remarquer, j'ai dû déclarer une autre fonction pour définir fibs. Normalement dans les langages fonctionnels on définit ce genre de fonction dans une expression let … in ou where. Du coup j'ai essayé d'implémenter ça en Acid, et j'ai traduit une expression (where (pi 3.14) (* 2 pi)) par l'AST Python équivalent à (lambda pi: 2 * pi)(3.14). Le problème c'est que cela ne marche pas si la valeur fait référence à elle même (notamment si elle désigne une fonction récursive, comme dans notre cas ici pour la suite de Fibonacci). Quelqu'un a une idée pour définir des valeurs dans un scope précis tout en autorisant la récursivité ?

Le problème c'est que cela ne marche pas si la valeur fait référence à elle même (notamment si elle désigne une fonction récursive, comme dans notre cas ici pour la suite de Fibonacci).

Je sais pas ce que tu as fais mais si ça marche bien en Python. Je t'ai fait un exemple plus haut : fact = lambda n: 1 if n==0 else n*fact(n-1)

En fait je voulais faire quelque chose du genre:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
(define fibs (lambda (n)
  (where
    (fibHelper (lambda (i x y)
      (if (== i 0)
        (list)
        (append x (fibHelper (- i 1) y (+ x y)))
        )
    ))
    (fibHelper n 1 1)
  )
))

… mais quand on essaye de traduire en Python à la main tu vois bien que c'est pas possible avec ma technique actuelle:

1
fibs = lambda n: (lambda fibHelper: fibHelper(n, 1, 1))(lambda i, x, y:  list() if i == 0 else [x] + ??? ))

C'est beaucoup de hack pour pas grand chose. Pourquoi ne pas définir tout bêtement une fonction au lieu d'une lambda ?

Les lambdas de Python sont bien trop limitées pour représenter les fonctions d'Acid.

+4 -0

Je pense que notre méthode de génération d'AST Python commence à avoir ses limites. Je sais que c'est pas bien compliqué de définir des fonctions nommées au lieu de lambdas, mais je ne suis pas sûr que ça soit adapté dans notre cas. A la rigueur si on veut rester sur du bytecode Python, on peut toujours générer manuellement le bytecode. Mais vu que vous avez dit hier que c'était pas une bonne chose pour des raisons de compatibilité, je propose de créer notre propre bytecode avec nos propres instructions (ou bien reprendre un ensemble d'instruction d'un autre langage fonctionnel).

Je ne me rends pas compte de la difficulté de créer son propre bytecode, dites moi si je vise trop haut.

Pour le moment le bytecode serait exécuté par une VM Python, mais à terme on pourra traduire vers de l'assembleur (j'ai jamais fait d'ASM, ilest temps que je m'y colle).

PS: Si on fait ça, pour le coup je vais avoir besoin d'aide. Autant les parsers et tout c'est pas bien compliqué, je comprends bien que c'est un niveau au dessus.

+1 -0

Ma question est : pourquoi te prendre la tête et vouloir déjà changer d’outil… pour une fonctionnalité qui n’est pas dans la spec (et si elle n’y est pas, ce n’est pas pour rien) ?

Dominus Carnufex

Soyons sérieux deux minutes : tu as sans doute passé beaucoup de temps sur cette spec dans le but de faire avancer les choses, et c'est tout à ton honneur. Mais :

  • Ce n'est pas parce que quelqu'un a décidé de la citer en première page qu'elle doit s'imposer à tout le monde : si quelqu'un est motivé par autre chose, laissez le faire !
  • Compiler vers du Python source, c'était sympa deux minutes le temps de faire un front-end sans écrire d'interpréteur, mais maintenant que c'est fait (ce qui avait un intérêt limité, vu que par ailleurs vous avez choisi la syntaxe la plus triviale possible), il est peut-être temps de passer à autre chose
  • Implémenter un langage qui n'a ni boucle, ni récursivité n'a que très peu d'intérêt. Ce n'est pas en enlevant de « la spec » tous les points qui sont plus difficiles qu'une traduction mot-à-mot vers Python que vous allez progresser.

Pour AlphaZeta : changer de cible est effectivement une excellente idée. Tu as plusieurs possibilités pour ça : écrire une VM, compiler vers une VM existante (LLVM par exemple), compiler en natif, ou compiler vers un autre langage que Python (parce que la traduction mot-à-mot, c'est pas passionnant), comme un sous-ensemble de C où on se restreindrait à une sorte d'assembleur lisible.

Dans tous les cas, tu vas sortir de ta zone de confort, et il faudra probablement lire un peu de choses sur la compilation. Tant mieux, le projet commence ! Cela dit, si j'étais toi, j'oublierais la compilation en natif ou vers LLVM pour l'instant. C'est une bonne cible pour plus tard, mais ça fait beaucoup de choses à apprendre pour tout de suite. Tu peux soit écrire une machine virtuelle (par exemple une machine à pile) et compiler vers ton bytecode, soit compiler vers un « C - - ». N'hésite pas à poser plus de questions !

+3 -1

Ma question est : pourquoi te prendre la tête et vouloir déjà changer d’outil… pour une fonctionnalité qui n’est pas dans la spec (et si elle n’y est pas, ce n’est pas pour rien) ?

Dominus Carnufex

Je veux changer d'outil parce que la traduction en AST Python n'était pas censée être utilisée à terme. De ce que j'ai compris c'était juste un petit hack pour avoir des résultats plus vite que si on avait commencé directement à compiler nous-mêmes. Donc un jour ou l'autre on devra changer. Autant changer maintenant donc, au lieu de s'embêter avec les limites de notre méthode actuelle, non ?

Et aussi quelle est la raison pour laquelle cette fonctionnalité n'est pas dans la spec ?

PS: grillé

Edit: Et pour LLVM, ça me tente mais j'aimerais bien faire moi-même mon bytecode, comme ça j'apprends plus :)

J'abandonne pas pour autant LLVM, parce que ça sera toujours beaucoup plus rapide et optimisé que ce qu'on fera, mais sur une autre branche alors, OK ? (parce que oui, la performance ne doit pas être une priorité pour l'instant je pense)

Edit: @Eusèbe: J'avais lu des choses sur C–, je n'ai pas trop compris pourquoi c'était utilisé pour les langages fonctionnels plus que LLVM ou une autre VM. Je me renseignerai davantage mais cela dit je suis plus attiré par la conception d'une VM à la main :)

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte