[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: In search of cool Scheme

From: Alejandro Forero Cuervo
Subject: Re: In search of cool Scheme
Date: Tue, 22 May 2001 23:46:31 -0500
User-agent: Mutt/1.2.5i


    > Symbolic manipulation, perhaps? Such as integration and differentiation?
    Ok - how about some examples?  I forgot to mention - I'm a Scheme
    beginner.  I'm definitely not qualified to program the cool Scheme I'm
    looking for.

What follows is some simple code that, given an equation, symbolically
derivates it.  The equation can include any of the following
operations: +, *, -, sin, expt, cos, log.  What's nice about this
example is that it is actually manipulating Scheme code: the equations
are represented using Scheme code.  The derivate function receives
Scheme code for an equation and returns Scheme code that can be
executed (eval'ed).  Look at the comments for more information.  Sorry
if its too long.

; General function to derivate a function.
; eq is the function you want to derivate and var is the symbol that changes.
; A function, as recognized by derivate, is defined as follows:
; Base cases:
;   function :== NUMBER
;   function :== SYMBOL
; Arithmetic cases:
;   function :== ( + function-list )
;   function :== ( - function function-list )
;   function :== ( * function-list )
; Exponentiation:
;   function :== ( expt function function )
;   function :== ( log function )
; Trigonometric cases:
;   function :== ( sin function )
;   function :== ( cos function )
; List of functions:
;   function-list :==
;   function-list :== function function-list
; Example:
; (function::derivate (list expt 'x (list * 5 'x)) 'x)
; => (+ (* (+ (* 5 1) (* 0 'x)) (log 'x) (expt 'x (* 5 'x))) (* (* 5 'x) 1 
(expt 'x (- (* 5 'x) 1))))
; Note that the results of this function might be particularily verbose.  We
; are working on a optimize function to address that problem.

(define function::derivate (lambda (eq d)
  (define (derivate-inside cont)
    (let derivate-real ((func eq) (var d))
      (if (list? func)
          ((equal? (car func) +)
            (cons + (map (lambda (term) (derivate-real term var)) (cdr func))))
          ((equal? (car func) -)
            (cons - (map (lambda (term) (derivate-real term var)) (cdr func))))
          ((equal? (car func) *)
            (if (equal? (length func) 2)
              (derivate-real (cadr func) var)
              (list +
                (list * (cadr func) (derivate-real (cons * (cddr func)) var))
                (cons * (cons (derivate-real (cadr func) var) (cddr func))))))
          ((equal? (car func) expt)
            (list +
              (list *
                (derivate-real (caddr func) var)
                (list log (cadr func))
                (list expt (cadr func) (caddr func)))
              (list *
                (caddr func)
                (derivate-real (cadr func) var)
                (list expt (cadr func) (list - (caddr func) 1)))))
          ((equal? (car func) log)
            (/ (derivate-real (cadr func) var) (cadr func)))
          ((equal? (car func) sin)
            (list * (derivate-real (cadr func) var) (cons (cos (cdr func)))))
          ((equal? (car func) cos)
            (list * -1 (derivate-real (cadr func) var) (cons sin (cdr func))))
            (cont 'unknown)))
        (if (equal? func var) 1 0))))
  (call-with-current-continuation derivate-inside)))

; To actually evaluate an equation, you'll want to call function::replace a few
; times and then call eval.
; For example, if you have an equation that uses X and you want to evaluate it
; where X has a value of 18, you do:
; (eval (function::replace (list + 'X 'X 1) 'X 18))
; => 37

(define function::replace (lambda (func var value)
  (if (list? func)
    (cons (car func) (map (lambda (term) (function::replace term var value)) 
(cdr func)))
    (if (equal? func var) value func))))

Hope I made sense and you like this example.  I think this example in
Perl would take more than the 40 lines it does in Scheme.

Another neat feature Scheme has is lazy evaluation.  The typical
example given on this subject involves infinite lists.  It goes along
the lines of the following:

(define (primes)

  (define (check-prime current number) (cond
    ((> (* current current) number)     #t)
    ((equal? 0 (modulo number current)) #f)
    (else                               (check-prime (+ 1 current) number))))

  (let build ((num 2))
    (if (check-prime 2 num) (cons num (delay (build (+ 1 num))))
      (build (+ 1 num)))))

When you evaluate (primes), it returns you a list with all the prime
numbers (granted, this could be optimized muchly).  To get the number
in a given node, use 
  (car node) .
To get the next node, use
  (force (cdr node) .

I know that example doesn't look that great.  However, in -big- real
projects --those that take much more than 10 lines--, lazy evaluation
is truly really seriously honestly great to optimize code without
obfuscating it or to simplify code without losing performance.

Scheme might not be that great for simple examples when compared with
Perl --I wouldn't know how to reproduce the code in my signature in
Guile: how can I check to see which bits are on on a given char?-- but
it is awesome for keeping things simple.

I was about to make some sort of comparation of Scheme with Perl, but
I guess that's not called for.

Good luck! :)


The mere formulation of a problem is far more essential than its solution.
      -- Albert Einstein.

$0='!/sfldbi!yjoV0msfQ!sfiupob!utvK'x44;print map{("\e[7m \e[0m",chr ord
"219CC1CCC033E7E660198CCE4E66798303873CCE60F3387$F"#Don't you love Perl?

Attachment: pgp9z82L4Qoui.pgp
Description: PGP signature

reply via email to

[Prev in Thread] Current Thread [Next in Thread]