|
From: | Jean Abou Samra |
Subject: | Re: débuts difficiles avec scheme |
Date: | Mon, 5 Jul 2021 08:50:42 +0200 (CEST) |
Le 04/07/2021 22:25, Martial R <martialr@gmail.com> a écrit :
Depuis le temps que je me disais faudrait que je regarde comment introduire les conditions.Oui vu pendant le café Lily mais ... pfuit .... oublié...
Langage d'extension de LilyPond. On peut tout faire en Scheme.
Le # introduit une _expression_ Scheme.
#(set-global-staff-size 18)
\tag #'edition (
\shape #'((0 . 0) (0.1 . 0.3) (0.1 . 0.5) (0 . 1.0)) Slur
À l'intérieur d'une _expression_ Scheme, #{ ... #}
passe en syntaxe LilyPond.
#(skip-of-length #{ { c'8 d' e' f' e' d' } #})
Nombres.
Chaînes de caractères.
"Sonate 4"
"Sonate 4"
Introduits par le caractère ;
.
; Ceci est ignoré.
4 ; Moi aussi, je suis ignoré.
4
(/ 2 2)
1
Syntaxe : (procédure argument1 argument2 ...)
+
, -
, *
, /
sont des procédures (fonctions).
LilyPond : \fonction argument1 argument2 ...
\relative c' { c d e d c }
Scheme : (fonction argument1 argument2 ...)
(+ 2 2)
4
Les parenthèses ne sont pas facultatives !
+ 2 2
2
(4)
wrong-type-arg (#f Wrong type to apply: ~S (4) (4))
(- (/ 2 3) (/ 3 5))
1/15
$1 - (5 \times 6) - (3 \times (4 + 3/12))$
(- 1 (* 5 6) (* 3 (+ 4 (/ 3 12))))
-167/4
En Scheme, tout est _expression_.
()(((((()))))(( )((())((()( )()) )(() ())()((()((((( ())( ()() ())()(()(())(( )))((())((())))( (()())((())) )))) )(() ))()()(()(()( ()((() ))((( ((()()(())(() ))()))(()))() (())((())()( ))() ())( (()) )) )(( (()) )))))((((()(( ))()()()))())) )(() )(() ()(( )(( ( ()( (()) )()(((()))(()( )()(()()()()()( ((() ()() )()) ))) ) ()( ())) )()(()()((())( (()()(((())))) ()))())))(((()()( ))))())(( ))( ((( ((((()()) ))(((())(()(( (())((()))(())) )(((((()(((()())( )()) )() ))) )))( )()))()()() ))()))))((())) ()() (()) ()() ()( )(( (()) )(((())(()) )))()()((()(()( )))( ))(( ))(( ()) )() ()(( ))((((()())) )(()(()()))) ()(( ()(( )()( ((( ))( (()( ()()))((()()() ((()())))))()))) ()() ))() ()()()(())() ((( )() ())()(()())( ((())))(((())(() )(()()((())((( ()() )()( )))))())((()(( )() ()( ())(()(())))))
Trois formes possibles pour une _expression_ :
1.
(fonction argument1 argument2 ...)
2.
(fonction argument1
argument2
...)
3.
(fonction
argument1
argument2
...)
(+ (* 3 456 123)
(/ 6 (- 10 7))
(-
(* 30 4012 (+ 123 5642))
20
50003))
694043646
Syntaxe :
(define nom valeur)
Équivalent LilyPond : clarinette = { ... }
.
On peut ensuite réutiliser la valeur.
(define x+|^ 34)
x+|^
34
Un moyen de prendre des décisions.
Syntaxe :
(if condition _expression_-si-oui _expression_-si-non)
(if (= 3 4)
"3 = 4, ça alors !"
"3 ≠ 4, vraiment ?")
"3 ≠ 4, vraiment ?"
(= 3 3)
#t
Deux valeurs booléennes : #t
(true, vrai) et #f
(false, faux).
=
: égalité numérique.
(= 3 3.0)
#t
equal?
: le plus général, s'applique à tous les types.
(equal? "Bonjour" "Bonjour")
#t
Toutes les possibilités : <
, <=
, >
, >=
.
(>= 3 3)
#t
not
: négation.
and
: toutes les conditions sont vérifiées.
or
: au moins une des conditions est vérifiée.
(define x 50)
(if (and (>= x 0)
(<= x 100))
"x est bien un pourcentage."
"Pourcentage suspect (pas entre 0 et 100).")
"x est bien un pourcentage."
(define x 1000000000000000)
(if (or (>= x 100000)
(<= x -100000))
"C'est trop grand pour moi."
"Je peux m'en sortir.")
"C'est trop grand pour moi."
(define x 0)
(if (not (= x 0))
"Erreur : x devrait valoir 0.")
La dernière _expression_ n'a pas de valeur particulière lorsque $x$ est entre -100000 et 100000. Mais elle a tout de même une valeur !
*unspecified*
(define x 42)
(unspecified?
(if (or (>= x 100000)
(<= x -100000))
"C'est trop grand pour moi."))
#t
*unspecified*
prend son intérêt lorsque l'_expression_ ne renvoie pas de valeur particulière.
Exemple : display
affiche une chaîne et renvoie *unspecified*
.
(define x 10)
(if (or (>= x 100000)
(<= x -100000))
(display "Erreur : c'est trop grand pour moi."))
Cas typique :
(if (= direction LEFT)
[aligne grob à gauche...]
(if (= direction CENTER)
[aligne grob au milieu...]
(if (= direction RIGHT)
[aligne grob à droite...]
[erreur : direction invalide...])))
Syntaxe plus pratique :
(cond
(condition1 valeur1)
(condition2 valeur2)
(condition3 valeur3)
...)
La dernière condition peut être else
.
(define n -1)
(cond
((= n 0)
"Aucun")
((= n 1)
"Un seul")
((> n 1)
"Plusieurs")
(else
"On attendait un nombre positif"))
"On attendait un nombre positif"
Syntaxe :
(define (nom argument1 argument2 ...)
...)
(define (double x)
(* 2 x)
)
(double 4)
8
(define c 299792458)
(define (E m)
(* m (expt c 2)))
(E 56)
5033029000926178784
Le corps de la fonction est une suite d'expressions. La valeur de la dernière est renvoyée.
(define (double x)
(display "Fonction double appelée avec le paramètre : ")
(display x)
(newline)
(* 2 x)
)
(double 4)
Fonction double appelée avec le paramètre : 4
« Locales » : disponibles seulement dans une certaine partie du code.
Syntaxe :
(let ((variable1 valeur1)
(variable2 valeur2)
(variable3 valeur3)
...)
expression1
expression2
...)
let
se reconnaît visuellement.
(let (xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx)
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx)
(define (loto)
(let ((x (random 2))
(y (random 2)))
(display
(if (and (= x 1)
(= y 1))
"Chance !"
"Perdu."))))
(loto)
Perdu.
(let ((tirage1 (random 10))
(tirage2 (random (+ tirage1 1))))
(display
(if (eqv? tirage1 tirage2)
"Chance !"
"Perdu.")))
unbound-variable (#f Unbound variable: ~S (tirage1) #f)
Avec let
, toutes les valeurs sont évaluées, puis les variables sont affectées.
let*
affecte les variables l'une après l'autre.
(let* ((tirage1 (random 10))
(tirage2 (random (+ tirage1 1))))
(display
(if (= tirage1 tirage2)
"Chance !"
"Perdu.")))
Perdu.
Forme typique d'une fonction :
(define (fonction paramètres...)
(let* ((variable1 ...)
(variable2 ...)
(variable3 ...)
(variable4 ...)
encore beaucoup de variables...)
une _expression_ simple et courte))
Exemple réel :
(define (highlight::markup grob)
(let* ((x-extent (ly:grob-property grob 'X-extent))
(x-start (interval-start x-extent))
(x-end (interval-end x-extent))
(y-extent (ly:grob-property grob 'Y-extent))
(y-start (interval-start y-extent))
(y-end (interval-end y-extent))
(blot (ly:grob-property grob 'blot))
(color-gradient (ly:grob-property grob 'color-gradient))
(left-color (ly:grob-property grob 'left-color))
(right-color (ly:grob-property grob 'right-color))
(path
`((moveto ,(+ x-start blot) ,y-start)
(lineto ,(- x-end blot) ,y-start)
(curveto ,x-end ,y-start ,x-end ,y-start ,x-end ,(+ y-start blot))
(lineto ,x-end ,(- y-end blot))
(curveto ,x-end ,y-end ,x-end ,y-end ,(- x-end blot) ,y-end)
(lineto ,(+ x-start blot) ,y-end)
(curveto ,x-start ,y-end ,x-start ,y-end ,x-start ,(- y-end blot))
(lineto ,x-start ,(+ y-start blot))
(curveto ,x-start ,y-start ,x-start ,y-start ,(+ x-start blot) ,y-start))))
(if (null? color-gradient)
(make-path-markup 0 path)
(make-gradient-path-markup left-color right-color path))))
(let ((a 5))
(+ a 15))
20
Oublier une parenthèse.
(let ((a 5))
(+ a 15))
20
Déplacer une parenthèse.
(let
(
(a 5)
(+ a 15)
)
)
syntax-error (let bad let #(#f 0 7) (let ((a 5) (+ a 15))) #f)
Omettre des parenthèses.
(let ((a 5))
(+ a 15))
20
Forme la plus simple :
(list élément1 élément2 élément3 ...)
(list 0 1 2 3 4 "Bonjour")
(0 1 2 3 4 "Bonjour")
Autre forme, qui fonctionne pour les nombres, chaînes et booléens littéraux :
'(élément1 élément2 élément3 ...)
'(0 1 2 3 "Bonjour")
(0 1 2 3 "Bonjour")
(list (+ 1 1)
(+ 2 3))
(2 5)
'((+ 1 1)
(+ 2 2))
((+ 1 1) (+ 2 2))
length
: longueur d'une liste.
(length '(0 1 2 3 "Bonjour"))
5
reverse
: la liste à l'envers.
(reverse '(0 1 2 3))
(3 2 1 0)
list-ref
: accès à un élément (le premier à l'index 0).
(list-ref '(1 2 3 4)
2)
3
list-ref
est à apprendre… et oublier !
map
: applique une transformation à tous les éléments d'une liste.
On passe la transformation comme une fonction.
(map fonction liste)
(define (double x)
(* 2 x))
(map double '(0 1 2 3))
(0 2 4 6)
On peut même passer plusieurs listes.
(define (anniversaire personne date)
(display personne)
(display " fête son anniversaire le ")
(display date)
(newline))
(map anniversaire
'("Amélie" "Jules" "Jonathan")
'("13 janvier" "9 novembre" "30 février"))
Amélie fête son anniversaire le 13 janvier Jules fête son anniversaire le 9 novembre Jonathan fête son anniversaire le 30 février (#<unspecified> #<unspecified> #<unspecified>)
for-each
est comme map
, mais le résultat de la fonction n'est pas conservé.
(define (anniversaire personne date)
(display personne)
(display " fête son anniversaire le ")
(display date)
(newline))
(for-each anniversaire
'(Amélie Jules Jonathan)
(circular-list "13 janvier"))
Amélie fête son anniversaire le 13 janvier Jules fête son anniversaire le 13 janvier Jonathan fête son anniversaire le 13 janvier
filter
: garde seulement les éléments d'une liste qui vérifient une condition.
(even? 2)
#t
(filter even? '(0 1 2 3))
(0 2)
lambda
sert à créer une fonction sans lui donner de nom.
(lambda (paramètre1 paramètre2 ...)
...)
Ainsi,
(define (fonction paramètre1 paramètre2 ...)
...)
est un raccourci pour
(define fonction
(lambda (paramètre1 paramètre2 ...)
...))
(map
(lambda (x)
(* 2 x))
'(0 1 2 3))
(0 2 4 6)
(for-each
(lambda (personne date)
(display personne)
(display " fête son anniversaire le ")
(display date)
(newline))
'(Amélie Jules Jonathan)
'("13 janvier" "9 novembre" "30 février"))
Amélie fête son anniversaire le 13 janvier Jules fête son anniversaire le 9 novembre Jonathan fête son anniversaire le 30 février
Les objets graphiques (Graphical Objects, grobs) possèdent des propriétés.
\override NoteHead.color = "red"
Une propriété peut voir sa valeur calculée à partir d'autres propriétés.
Pour cela, on lui affecte une fonction.
\override NoteHead.color =
#(lambda (grob)
...)
\override NoteHead.color =
#(lambda (grob)
...)
grob est un objet graphique, avec des propriétés. On peut les lire :
(ly:grob-property grob propriété)
propriété est le nom d'une propriété précédé d'un '
.
(ly:grob-property grob 'staff-position)
\version "2.22.0" \layout { \context { \Voice \override NoteHead.color = #(lambda (grob) (let ((ligne-portée (ly:grob-property grob 'staff-position))) (cond ((= ligne-portée -8) "red") ((= ligne-portée -7) "blue") ((= ligne-portée -6) "green") ((= ligne-portée -5) "orange") ((= ligne-portée -4) "purple") ((= ligne-portée -3) "grey") ((= ligne-portée -2) "salmon") (else "black")))) } } \relative { \time 3/4 a8 b cis b a4 b fis' b, c8 d e d c4 d2. e8 fis g g fis e fis cis cis dis e4 e8 fis g fis e fis a b cis b a4 g8 a b a g4 fis8 g a g fis4 }
https://www.gnu.org/software/guile/learn/
https://scheme-book.ursliska.de/introduction/index.html
https://lilypond.org/doc/v2.22/Documentation/extending/
[Prev in Thread] | Current Thread | [Next in Thread] |