On peut définir le prédicat
avez-vous? qui, étant donnés un
prédicat et une liste, rend vrai si, et seulement si, il existe une
occurrence dans la liste donnée qui vérifie le prédicat donné. Par
exemple:
(avez-vous? odd? (list 4 2 1 3)) ->
#T
(avez-vous? odd? (list 4 2)) ->
#F
Cette fonction se définit très facilement (ce n'est qu'un exercice de
révision):
;;;
;;;
;;;
(define (avez-vous? test? L)
(if (pair? L)
(if (test? (car L))
#t
(avez-vous? test? (cdr L)))
#f))
La fonction précédente fait un peu penser au gag de celui qui
répond « oui » lorsqu'on lui demande « avez-vous l'heure? ». En
fait, on peut vouloir définir la fonction
val qui, étant
donnés un prédicat et une liste,
-
rend faux lorsqu'il n'existe pas d'élément de la liste
donnée qui vérifie le prédicat donné,
- lorsqu'il existe un tel élément, rend une de ses occurrences
--- choisissons la première --- qui vérifient le prédicat donné.
Par exemple:
(val odd? (list 4 2 1 3)) ->
1
(val odd? (list 4 2)) ->
#F
Cette fonction, qui rend
#f dans certains cas et une valeur
non booléenne dans d'autres cas, est appellée un
semi-prédicat. Sa définition peut être:
;;;
;;;
;;;
(define (val test? L)
(if (pair? L)
(if (test? (car L))
(car L)
(val test? (cdr L)))
#f))
Noter la signature de la fonction avec son «
+ #f » qui
indique un semi-prédicat. Noter aussi que, classiquement,
contrairement aux prédicats, les noms des semi-prédicats ne finissent
pas par un point d'interrogation.
Un autre exemple:
member est une primitive de Scheme (cf.
carte de référence) dont la
spécification est:
;;;
;;;
;;;
Exemples d'application:
(member 3 (list 2 3 1 3 2)) ->
(3 1 3 2)
(member 1 (list 2 3 1)) ->
(1)
(member 3 (list 2 1)) ->
#F
La définition pouvant être:
(define (member v L)
(if (pair? L)
(if (equal? v (car L))
L
(member v (cdr L)))
#f))
En fait, dans une alternative, toute condition qui n'a
pas la valeur
#f a une valeur de vérité Vrai.
Ainsi, en utilisant la fonction
val que nous avons définie plus haut:
(if (val odd? (list 4 2 1 3))
"il existe une valeur impaire"
"il n'existe pas de valeur impaire")
-->
il existe une valeur impaire
et
(if (val odd? (list 4 2))
"il existe une valeur impaire"
"il n'existe pas de valeur impaire")
-->
il n'existe pas de valeur impaire
Nous voudrions définir le semi-prédicat
index qui, étant donnés
un élément et une liste, rend l'index de la première occurrence de cet
élément dans la liste s'il existe un tel élément et rend
#f
sinon (dans une liste, l'index de son premier élément est égal à 1,
l'index de son deuxième élément est égal à 2...). Par exemple:
(index 2 (list 1 2 3)) ->
2
(index 4 (list 1 2 3)) ->
#F
Cette fonction peut être définie par:
;;;
;;;
;;;
;;;
(define (index elm L)
(if (pair? L)
(if (equal? elm (car L))
1
(let ((index-cdr-L (index elm (cdr L))))
(if index-cdr-L
(+ 1 index-cdr-L)
#f)))
#f))
Noter l'utilisation de la variable
index-cdr-L:
-
dans le if, elle est considérée comme une condition
(qui est vraie lorsque sa valeur n'est pas #f);
- dans (+ 1 index-cdr-L), on utilise sa « vraie » valeur.