Aucun message portant le libellé Scheme. Afficher tous les messages
Aucun message portant le libellé Scheme. Afficher tous les messages

samedi, mars 17, 2007

Calcul symbolique en Scheme

Il y a quelques semaines, j'ai commencé à lire "Structure and Interpretation of Computer Program" (ci-après référé comme SICP) de Harold Habelson et Gerald Jay & Julie Sussman du MIT. Ça n'avance pas très vite car c'est extrêmement dense. Il faut du temps pour lire et relire et pour faire les exercices. Pour ce faire, j'ai installé Guile comme interpréteur Scheme sur ma station de travail principale. J'utilise Kate comme éditeur. C'est pas ce qu'il y a de mieux mais ça fait la job.
Lisant le chapitre 2 de SICP, la section 2.3.2 a vraiment capté mon attention (en tant que physicien de formation): Elle porte sur le calcul symbolique. Je n'avais jamais utilisé un langage qui permettait ceci sauf peut-être le langage interne de Mathematica (dont l'ancêtre a été écrit en Lisp dont Scheme est un dialecte). Pour m'assurer de bien comprendre, j'ai fait l'exercice 2.56. J'ai par la suite tenté de l'étendre pour faire la dérivation de la fonction sinus. Initialement j'avais écris:

    ;Definition for sine

(define (sine? x)
(and (pair? x) (eq? (car x) 'sin)))

(define (sine-argument angle) (car angle))

(define (make-sine angle)
(cond ((=number? angle 'pi) 0)
((=number? angle 0) 0)
(else (cons 'sin angle))))

(define (make-cosine angle)
(cond ((=number? angle 'pi ) 1)
((=number? angle 0) 1)
(else (cons 'cos angle))))


mais sine-argument retournait toujours (x) au lieu de x. Ce qui faisait planter deriv un peu plus loin. Après avoir fouillé pas mal, et lu et relu une obscure note de bas de page. J'ai trouvé le bobo: car retourne toujours un élément unique entouré de parenthèses. Pour retourné un élément unique sans parenthèses, il faut utiliser list-ref.
On aura:

(car '(a b)) -> (a)
(list-ref '(a b) 0) -> a


Une fois cette modification faite, on obtient la solution pour 2.56 plus le cas pour la fonction sinus:

(define (variable? x) (symbol? x))

(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))

(define (make-sum a1 a2)
(cond ((=number? a1 0) a2)
((=number? a2 0) a1)
((and (number? a1) (number? a2)) (+ a1 a2))
(else (list '+ a1 a2))))

(define (=number? exp num)
(and (number? exp) (= exp num)))

(define (make-product m1 m2)
(cond ((or (=number? m1 0) (=number? m2 0)) 0)
((=number? m1 1) m2)
((=number? m2 1) m1)
((and (number? m1) (number? m2)) (* m1 m2))
(else (list '* m1 m2))))

(define (sum? x)
(and (pair? x) (eq? (car x) '+)))

(define (addend s) (cadr s))

(define (augend s) (caddr s))

(define (product? x)
(and (pair? x) (eq? (car x) '*)))

(define (multiplier p) (cadr p))

(define (multiplicand p) (caddr p))

; definitions for exponentiation

(define (make-exponentiation base exponent)
(cond ((=number? exponent 0) 1)
((=number? exponent 1) base)
(else (list '** base exponent))))

(define (base exponentiation) (cadr exponentiation))

(define (exponent exponentiation) (caddr exponentiation))

(define (exponentiation? x)
(and (pair? x) (eq? (car x) '**)))

;definitions for sine

(define (sine? x)
(and (pair? x) (eq? (car x) 'sin)))

;Here, car doesn't work but list-ref works(define (sine-argument angle) (list-ref angle 1))


(define (make-sine angle)
(cond ((=number? angle 'pi) 0)
((=number? angle 0) 0)
(else (cons 'sin angle))))

(define (make-cosine angle)
(cond ((=number? angle 'pi ) 1)
((=number? angle 0) 1)
(else (cons 'cos angle))))

(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp)
(if (same-variable? exp var) 1 0))
((sum? exp)
(make-sum (deriv (addend exp) var)
(deriv (augend exp) var)))
((product? exp)
(make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (deriv (multiplier exp) var)
(multiplicand exp))))
((exponentiation? exp)
(make-product
(make-product (exponent exp)
(make-exponentiation (base exp)
(make-sum (exponent exp) -1)))
(deriv (base exp) var)))
((sine? exp)
make-product (deriv (sine-argument exp) var)
(make-cosine (sine-argument exp)) )
(else
(error "unknown expression type -- DERIV" exp))))



Je vais essayer d'étendre encore plus ce programme dès que j'en aurai le temps. À suivre...

mercredi, février 14, 2007

Sur les langages

Deux thèmes, un seul mot ce matin: langages.
Je prends des cours de chinois. Un soir par semaine. C'est peu mais c’est intellectuellement stimulant.

Ce que je trouve intéressant, c'est de comparer comment on dit une chose équivalente d'une langue à l'autre. Je parle couramment le français et l'anglais et j'ai déjà étudié le japonais et l'allemand. Je peux donc faire quelques comparaisons.
En japonais et en chinois, il y a des mots d'énumération. C'est un mot que l'on met entre le cardinal et l'objet compté et qui nous renseigne, un peu, sur la nature de l'objet compté. En japonais comme en chinois il existe un mot réservé au compte d'objet de forme ronde ou sphérique. Si on vous mentionne un mot que vous ne connaissez pas mais qui est précédé du mot d'énumération (et d’un cardinal!) pour les objets ronds ou sphériques, vous faites l'acquisition d'une information supplémentaire, qui jumelée au contexte, vous permet de (peut-être) deviner le sens du mot inconnu. Pratique.
Prenez aussi par exemple les pronoms relatifs en français. Avez-vous pensez ce que la langue serait sans eux? La phrase "La femme dont le mari est gros.." deviendrait "La femme, elle a un mari gros, ...". Même si les deux phrases ont la même signification, la première forme sonne mieux. Un petit mot, "dont", influence la syntaxe et la rend expressive (si vous trouvez un meilleur exemple, dites-le moi).

Le concept « d'expressivité par la syntaxe » n'existe pas que pour les langages humains. Il existe aussi pour les langages informatiques. On a qu'a comparer les langages de type fonctionnel (F#, ML, Erlang, Haskell, ...) aux langages impératifs (Java, C, ...). Leurs syntaxes sont radicalement différentes. Ils parviennent tous à exprimer les mêmes concepts mais sans les mêmes structures. Pour certains types de programmes, les langages de type fonctionnel mènent à des solutions plus élégantes.

Je m’intéresse pas mal ces temps-ci aux langages fonctionnels. J’étudie Lisp/Scheme et j’aimerais bien avoir le temps de jeter un coup d’œil à Haskell ou Erlang (ce dernier se prêtant pas mal bien à la programmation concurrentielle). Je trouve stimulant d’être exposé à autre chose que des langages impératifs auxquels tous sont familiers. Je suis convaincu qu’apprendre sur les langages fonctionnels fera que je serai plus productif et clair avec les langages impératifs que j’utilise les plus souvent.


En Lisp, en écrivant une macro on créé une nouvelle structure du langage qui altère la structure, la rendant plus expressive. Cette caractéristique du langage n'existe pas dans les langages de type impératifs.

En Haskell, par le biais du « pattern matching » on peut décrire à l’intérieur de la signature d’une fonction des cas d’utilisation de celle-ci plutôt que de recourir à une structure de type « case » dans le corps de la fonction.

Voilà pour ce matin. Si je pense à autre chose, je l'écrirai.

dimanche, février 11, 2007

Étapes pour installer DrScheme sous Gentoo

J'ai essayé d'installer DrScheme sur ma station de travail cet après-midi. Installer DrScheme simplement à partir de "emerge -aDv drscheme" s'avéra problématique, le e-build plante à chaque fois.
Jetant un coup d'oeil sur les forums de Gentoo, j'ai trouvé la solution mais quelques modifications s'imposaient. Voilà la procédure:

  • wget http://bugs.gentoo.org/attachment.cgi?id=93091
  • cp attachment.cgi?id=93091 drscheme-352-raw-LDFLAGS.patch
  • patch drscheme-352-r2.ebuild drscheme-352-raw-LDFLAGS.patch (Il y aura une erreur au 1er chunk mais elle peut être ignorée)
  • ebuild drscheme-352-r2.ebuild digest
  • ACCEPT_KEYWORDS="~x86" emerge -a =x11-libs/libXft-2.1.12
  • emerge -a drscheme
  • etc-update
  • cp drscheme-352-r2.ebuild /usr/local/portage/

C'est aussi simple que ça. Je peux donc faire les exemples dans le livre '"Structure and Interpretation of Computer Programs"