#lang racket

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

;;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 regla_a
  (lambda (signo contexto_i contexto_d)
    (let ((lista-contexto-izqdo (string->list contexto_i))
          (lista-contexto-dcho (string->list contexto_d))
          )
      (if (char=? signo #\a)
          (if (or (null? lista-contexto-izqdo)(null? lista-contexto-dcho))
              (concatenar #\a)
              (if (and (char=? (last lista-contexto-izqdo) #\b)(char=? (first lista-contexto-dcho) #\c))
                  (concatenar "abc")
                  (concatenar #\a)
                  )
              )
          #f)
      )
    ))
(define regla_b
  (lambda (signo contexto_i contexto_d)
    (if (char=? signo #\b)
        (concatenar #\c)
        #f)
    ))
(define regla_c
  (lambda (signo contexto_i contexto_d)
    (if (char=? signo #\c)
        (concatenar #\b)
        #f)
    ))
(define regla_+
  (lambda (signo contexto_i contexto_d)
    (if (char=? signo #\+)
        (concatenar #\+)
        #f)
    ))
(define regla_-
  (lambda (signo contexto_i contexto_d)
    (if (char=? signo #\-)
        (concatenar #\-)
        #f)
    ))
;;5. Se aplica una de las tres reglas
(define aplicar-reglas
  (lambda (signo contexto_i contexto_d)
    (or
     (regla_a signo contexto_i contexto_d)
     (regla_b signo contexto_i contexto_d)
     (regla_c signo contexto_i contexto_d)
     (regla_+ signo contexto_i contexto_d)
     (regla_- signo contexto_i contexto_d)
     )
    ))
;;6. Transformación
;;6.1 Contextos como substrings
(define contexto_i
  (lambda (ristra indice-signo)
    (let go ((i 0)
             (j (string-length ristra))
             (contexto "")
             )
      (if (= i j)
          contexto
          (if (= i indice-signo)
              contexto
              (go (add1 i) j (string-append contexto (substring ristra i (add1 i))))
              )
          )
      )
    ))
(define contexto_d
  (lambda (ristra indice-signo)
    (let go ((i 0)
             (j (string-length ristra))
             (contexto "")
             )
      (if (= i j)
          contexto
          (if (= i indice-signo)
              (substring ristra (add1 i) (string-length ristra))
              (go (add1 i) j (string-append contexto (substring ristra i (add1 i))))
              )
          )
      )
    ))
(define contextos
  (lambda (indice-signo ristra)
    (let ((context_i (contexto_i ristra indice-signo))
          (context_d (contexto_d ristra indice-signo))
          )
      (values
       context_i
       context_d
       )
      )
    ))
;;6.2 Procedimiento auxiliar de transformación
(define transformar
  (lambda (ristra)
    (let go ((i 0)
             (j (string-length ristra))
             (S "")
             )
      (if (= i j)
          S
          (let-values 
              ([(signo) (string-ref ristra i)]
               [(cont_i cont_d) (contextos i ristra)]
               )
            (go (add1 i) j (concatenar S (aplicar-reglas signo cont_i cont_d)))
            )
          )
      )
    ))
;;6.3 Método de transformación
(define transformacion
  (lambda (tesis)
    (if (ristra? tesis)
        (transformar tesis)
        (printf "~a ha de ser una tesis~n" tesis)
        )
    ))


;;Un ejemplo:
(let go ((i 0)
           (j 6)
           (S "+c-abac-a+a+a-a+a")
           )
    (if (= i j)
        (printf "~a: ~a~n" i S)
        (begin
          (printf "~a: ~a~n" i S)
          (go
           (add1 i) j
           (transformacion S)
           )
          )
        )
    )      