#lang racket

;;1. Hay que contar con un vocabulario
(define vocabulario (list #\a #\b))

;;2. Operación para formar expresiones compuestas
(define-syntax concatenar
  (syntax-rules ()
    [(concatenar x ...)
     (apply string-append
            (map
             (lambda (s)
               (cond
                 ((char? s) (string s))
                 ((string? s) s)
                 (else #f)
                 ))
             (list x ...))
            )
     ]
    ))
;;3. Predicado de tipo
(define-syntax ristra?
  (syntax-rules ()
    [
     (ristra? s)
     (andmap
      (lambda (char)
        (if (member char vocabulario)
            #t
            #f))
      (string->list s))
     ]
    ))
;;4. Reglas de producción
(define a->ab
  (lambda (char)
    (if (char=? char (first vocabulario));#\a)
        (concatenar (first vocabulario) (second vocabulario));#\a #\b)
        #f)
    ))
(define b->a
  (lambda (char)
    (if (char=? char (second vocabulario));#\b)
        (concatenar (first vocabulario));#\a)
        #f)
    ))
;;5. Se aplica una de las dos reglas
(define aplicar-reglas
  (lambda (char)
    (or
     (a->ab char)
     (b->a char)
     )))
;;6. Procedimiento auxiliar de transformación
(define transformar
  (lambda (lista-char)
    (if (null? lista-char)
        ""
        (concatenar
         (aplicar-reglas (first lista-char))
         (transformar (rest lista-char))
         )
        )
    ))
;;6. Método de transformación
(define transformacion
  (lambda (tesis)
    (if (ristra? tesis)
        (transformar (string->list tesis))
        (printf "~a ha de ser una tesis~n" tesis)
        )
    ))


;;Un ejemplo:
(let go ((i 0)
           (j 10)
           (S "b")
           )
    (if (= i j)
        (printf "~a~n" S)
        (begin
          (printf "~a~n" S)
          (go
           (add1 i) j
           (transformacion S)
           )
          )
        )
    )      