2010-01-15 15 views
11

He estado trabajando en una implementación del Mandelbrot Set en varios idiomas diferentes. Tengo una implementación que funciona en C++, C#, Java y Python, pero la implementación de Common Lisp tiene algunos errores que no puedo entender. Genera el conjunto, pero en algún lugar de la tubería el conjunto se distorsiona. He probado y sé con cerca de con la certeza de que el archivo I/O CLO no es el problema, es poco probable pero posible, lo he probado muy bien.Implementación del conjunto Mandelbrot en Common Lisp

Tenga en cuenta que la intención de estas implementaciones es compararlas entre sí, por lo que trato de mantener las implementaciones de código lo más similares posible para que sean comparables.

El conjunto de Mandelbrot (en este caso generado por la implementación de Python):

http://www.freeimagehosting.net/uploads/65cb71a873.png http://www.freeimagehosting.net/uploads/65cb71a873.png "conjunto de Mandelbrot (generada por Python)"

Pero mi programa Common Lisp genera esto:

http://www.freeimagehosting.net/uploads/50bf29bcc9.png http://www.freeimagehosting.net/uploads/50bf29bcc9.png "Common Lisp El conjunto de Mandelbrot distorsionado de la versión "

El error es idéntico tanto en Clisp como en SBCL.

CÓDIGO:

Common Lisp:

(defun mandelbrot (real cplx num_iter) 
    (if (> (+ (* real real) (* cplx cplx)) 4) 
     1 
     (let ((tmpreal real) (tmpcplx cplx) (i 1)) 
     (loop 
      (setq tmpcplx (+ (* (* tmpreal tmpcplx) 2) cplx)) 
      (setq tmpreal (+ (- (* tmpreal tmpreal) (* tmpcplx tmpcplx)) 
       real)) 
      (setq i (+ i 1)) 
      (cond 
       ((> (+ (* tmpreal tmpreal) 
        (* tmpcplx tmpcplx)) 4) (return i)) 
       ((= i num_iter) (return 0))))))) 

(defun floordiv (dend sor) (/ (- dend (mod dend sor)) sor)) 

(defclass xbm() (
    (data :accessor data :initarg :data) 
    (dim :reader dim :initarg :dim) 
    (arrsize :reader arrsize :initarg :arrsize))) 

(defmethod width ((self xbm)) (third (dim self))) 

(defmethod height ((self xbm)) (second (dim self))) 

(defun generate (width height) 
    (let ((dims (list 0 0 0)) (arrsize_tmp 0)) 
     (setq dims (list 0 0 0)) 
     (setf (second dims) height) 
     (setf (third dims) width) 
     (setf (first dims) (floordiv (third dims) 8)) 
     (unless (= (mod width 8) 0) (setf (first dims) (+ (first dims) 1))) 
     (setq arrsize_tmp (* (first dims) (second dims))) 
     (make-instance 'xbm 
     :data (make-array arrsize_tmp :initial-element 0) 
     :dim dims 
     :arrsize arrsize_tmp))) 

(defun writexbm (self f) 
    (with-open-file (stream f :direction :output :if-exists :supersede) 
     (let ((fout stream)) 
     (format fout "#define mandelbrot_width ~d~&" (width self)) 
     (format fout "#define mandelbrot_height ~d~&" (height self)) 
     (format fout "#define mandelbrot_x_hot 1~&") 
     (format fout "#define mandelbrot_y_hot 1~&") 
     (format fout "static char mandelbrot_bits[] = {") 
     (let ((i 0)) 
      (loop 
       (if (= (mod i 8) 0) 
        (format fout "~& ") 
        (format fout " ")) 
       (format fout "0x~x," (svref (data self) i)) 
       (unless (< (setf i (+ i 1)) (arrsize self)) 
        (return t))))))) 

(defmethod setpixel ((self xbm) (x integer) (y integer)) 
    (if (and (< x (third (dim self))) (< y (second (dim self)))) 
     (let ((val (+ (floordiv x 8) (* y (first (dim self)))))) 
     (setf (svref (data self) val) (boole boole-ior (svref (data self) val) (ash 1 (mod x 8))))))) 

(defmethod unsetpixel ((self xbm) (x integer) (y integer)) 
    (if (and (< x (third (dim self))) (< y (second (dim self)))) 
     (let ((val (+ (floordiv x 8) (* y (first (dim self)))))) 
     (setf (svref (data self) val) (boole boole-xor (boole boole-ior 
      (svref (data self) val) (ash 1 (mod x 8))) (ash 1 (mod x 8))))))) 

(defmethod draw_mandelbrot ((xbm xbm) (num_iter integer) (xmin number) 
    (xmax number) (ymin number) (ymax number)) 

    (let ((img_width (width xbm)) (img_height (height xbm)) (xp 0)) 
     (loop 
     (if (< xp img_width) 
      (let ((xcoord (+ (* (/ xp img_width) (- xmax xmin)) xmin)) (yp 0)) 
       (loop 
        (if (< yp img_height) 
        (let (
         (ycoord (+ (* (/ yp img_height) (- ymax ymin)) ymin))) 
         (let ((val (mandelbrot xcoord ycoord num_iter))) 
          (if (> val 0) (unsetpixel xbm xp yp) (setpixel xbm xp yp))) 
         (setq yp (+ yp 1))) 
        (return 0))) 
       (setq xp (+ xp 1))) 
      (return 0))))) 

(defun main() 
    (let ((maxiter 0) (xmin 0) (xmax 0) (ymin 0) (ymax 0) (file nil) (xsize 0) (ysize 0) (picture nil)) 
     (format t "maxiter? ") 
     (setq maxiter (read)) 
     (format t "xmin? ") 
     (setq xmin (read)) 
     (format t "xmax? ") 
     (setq xmax (read)) 
     (format t "ymin? ") 
     (setq ymin (read)) 
     (format t "ymax? ") 
     (setq ymax (read)) 
     (format t "file path: ") 
     (setq file (read-line)) 
     (format t "picture width? ") 
     (setq xsize (read)) 
     (format t "picture height? ") 
     (setq ysize (read)) 
     (format t "~&") 
     (setq picture (generate xsize ysize)) 
     (draw_mandelbrot picture maxiter xmin xmax ymin ymax) 
     (writexbm picture file) 
     (format t "File Written.") 
     0)) 

(main) 

Y el más cercano a él es Python:

from xbm import * 

def mandelbrot(real_old,cplx_old,i): 
    real = float(real_old) 
    cplx = float(cplx_old) 
    if (real*real+cplx*cplx) > 4: 
     return 1 
    tmpreal = real 
    tmpcplx = cplx 
    for rep in range(1,i): 
     tmpb = tmpcplx 
     tmpcplx = tmpreal*tmpcplx*2 
     tmpreal = tmpreal*tmpreal - tmpb*tmpb 
     tmpcplx += cplx 
     tmpreal += real 
     tmpb = tmpcplx*tmpcplx + tmpreal*tmpreal 
     if tmpb > 4: 
     return rep+1 
    else: 
     return 0 

def draw_mandelbrot(pic, num_iter, xmin, xmax, ymin, ymax): 
    img_width = pic.width() 
    img_height = pic.height() 
    for xp in range(img_width): 
     xcoord = (((float(xp))/img_width) * (xmax - xmin)) + xmin 
     for yp in range(img_height): 
     ycoord = (((float(yp))/img_height) * (ymax - ymin)) + ymin 
     val = mandelbrot(xcoord, ycoord, num_iter) 
     if (val): 
      pic.unsetpixel(xp, yp) 
     else: 
      pic.setpixel(xp, yp) 

def main(): 
    maxiter = int(raw_input("maxiter? ")) 
    xmin = float(raw_input("xmin? ")) 
    xmax = float(raw_input("xmax? ")) 
    ymin = float(raw_input("ymin? ")) 
    ymax = float(raw_input("ymax? ")) 
    file = raw_input("file path: ") 
    xsize = int(raw_input("picture width? ")) 
    ysize = int(raw_input("picture height? ")) 
    print 
    picture = xbm(xsize, ysize) 
    draw_mandelbrot(picture, maxiter, xmin, xmax, ymin, ymax) 
    picture.writexbm(file) 
    print "File Written. " 
    return 0; 

main() 

[xbm.py] 

from array import * 

class xbm: 
    def __init__(self, width, height): 
     self.dim = [0, 0, 0] 
     self.dim[1] = height 
     self.dim[2] = width 
     self.dim[0] = self.dim[2]/8 
     if width % 8 != 0: 
     self.dim[0] += 1 
     self.arrsize = self.dim[0] * self.dim[1] 
     self.data = array('B', (0 for x in range(self.arrsize))) 
     self.hex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'] 
    def __nibbletochar__(self, a): 
     if a < 0 or a > 16: 
     return '0' 
     else: 
     return self.hex[a] 
    def setpixel(self, x, y): 
     if x < self.dim[2] and y < self.dim[1]: 
     self.data[(x/8) + (y * self.dim[0])] |= 1 << (x % 8) 
    def unsetpixel(self, x, y): 
     if x < self.dim[2] and y < self.dim[1]: 
     self.data[(x/8) + (y * self.dim[0])] |= 1 << (x % 8) 
     self.data[(x/8) + (y * self.dim[0])] ^= 1 << (x % 8) 
    def width(self): 
     return self.dim[2] 
    def height(self): 
     return self.dim[1] 
    def writexbm(self, f): 
     fout = open(f, 'wt') 
     fout.write("#define mandelbrot_width ") 
     fout.write(str(self.dim[2])) 
     fout.write("\n#define mandelbrot_height ") 
     fout.write(str(self.dim[1])) 
     fout.write("\n#define mandelbrot_x_hot 1") 
     fout.write("\n#define mandelbrot_y_hot 1") 
     fout.write("\nstatic char mandelbrot_bits[] = {") 
     for i in range(self.arrsize): 
     if (i % 8 == 0): fout.write("\n\t") 
     else: fout.write(" ") 
     fout.write("0x") 
     fout.write(self.__nibbletochar__(((self.data[i] >> 4) & 0x0F))) 
     fout.write(self.__nibbletochar__((self.data[i] & 0x0F))) 
     fout.write(",") 
     fout.write("\n};\n") 
     fout.close(); 

me pueden enviar el C++, C#, o el código de Java, así Necesito ser.

Gracias!

EDITAR: Gracias a la respuesta de Edmund, encontré el error: algo que se deslizó a través de las grietas en la transferencia. código modificado:

(defun mandelbrot (real cplx num_iter) 
    (if (> (+ (* real real) (* cplx cplx)) 4) 
     1 
     (let ((tmpreal real) (tmpcplx cplx) (i 1) (tmpb cplx)) 
     (loop 
      (setq tmpb tmpcplx) 
      (setq tmpcplx (+ (* (* tmpreal tmpcplx) 2) cplx)) 
      (setq tmpreal (+ (- (* tmpreal tmpreal) (* tmpb tmpb)) 
       real)) 
      (setq i (+ i 1)) 
      (cond 
       ((> (+ (* tmpreal tmpreal) 
        (* tmpcplx tmpcplx)) 4) (return i)) 
       ((= i num_iter) (return 0))))))) 

(defun floordiv (dend sor) (/ (- dend (mod dend sor)) sor)) 

(defclass xbm() (
    (data :accessor data :initarg :data) 
    (dim :reader dim :initarg :dim) 
    (arrsize :reader arrsize :initarg :arrsize))) 

(defun width (self) (third (dim self))) 

(defun height (self) (second (dim self))) 

(defun generate (width height) 
    (let ((dims (list 0 0 0)) (arrsize_tmp 0)) 
     (setq dims (list 0 0 0)) 
     (setf (second dims) height) 
     (setf (third dims) width) 
     (setf (first dims) (floordiv (third dims) 8)) 
     (unless (= (mod width 8) 0) (setf (first dims) (+ (first dims) 1))) 
     (setq arrsize_tmp (* (first dims) (second dims))) 
     (make-instance 'xbm 
     :data (make-array arrsize_tmp :initial-element 0) 
     :dim dims 
     :arrsize arrsize_tmp))) 

(defun writexbm (self f) 
    (with-open-file (stream f :direction :output :if-exists :supersede) 
     (let ((fout stream)) 
     (format fout "#define mandelbrot_width ~d~&" (width self)) 
     (format fout "#define mandelbrot_height ~d~&" (height self)) 
     (format fout "#define mandelbrot_x_hot 1~&") 
     (format fout "#define mandelbrot_y_hot 1~&") 
     (format fout "static char mandelbrot_bits[] = {") 
     (let ((i 0)) 
      (loop 
       (if (= (mod i 8) 0) 
        (format fout "~& ") 
        (format fout " ")) 
       (format fout "0x~x," (svref (data self) i)) 
       (unless (< (setf i (+ i 1)) (arrsize self)) 
        (return t))))))) 

(defun setpixel (self x y) 
    (if (and (< x (third (dim self))) (< y (second (dim self)))) 
     (let ((val (+ (floordiv x 8) (* y (first (dim self)))))) 
     (setf (svref (data self) val) (boole boole-ior (svref (data self) val) (ash 1 (mod x 8))))))) 

(defun unsetpixel (self x y) 
    (if (and (< x (third (dim self))) (< y (second (dim self)))) 
     (let ((val (+ (floordiv x 8) (* y (first (dim self)))))) 
     (setf (svref (data self) val) (boole boole-xor (boole boole-ior 
      (svref (data self) val) (ash 1 (mod x 8))) (ash 1 (mod x 8))))))) 

(defun draw_mandelbrot (xbm num_iter xmin xmax ymin ymax) 

    (let ((img_width (width xbm)) (img_height (height xbm)) (xp 0)) 
     (loop 
     (if (< xp img_width) 
      (let ((xcoord (+ (* (/ xp img_width) (- xmax xmin)) xmin)) (yp 0)) 
       (loop 
        (if (< yp img_height) 
        (let (
         (ycoord (+ (* (/ yp img_height) (- ymax ymin)) ymin))) 
         (let ((val (mandelbrot xcoord ycoord num_iter))) 
          (if (> val 0) (unsetpixel xbm xp yp) (setpixel xbm xp yp))) 
         (setq yp (+ yp 1))) 
        (return 0))) 
       (setq xp (+ xp 1))) 
      (return 0))))) 

(defun main() 
    (let ((maxiter 0) (xmin 0) (xmax 0) (ymin 0) (ymax 0) (file nil) (xsize 0) (ysize 0) (picture nil)) 
     (format t "maxiter? ") 
     (setq maxiter (read)) 
     (format t "xmin? ") 
     (setq xmin (read)) 
     (format t "xmax? ") 
     (setq xmax (read)) 
     (format t "ymin? ") 
     (setq ymin (read)) 
     (format t "ymax? ") 
     (setq ymax (read)) 
     (format t "file path: ") 
     (setq file (read-line)) 
     (format t "picture width? ") 
     (setq xsize (read)) 
     (format t "picture height? ") 
     (setq ysize (read)) 
     (format t "~&") 
     (setq picture (generate xsize ysize)) 
     (draw_mandelbrot picture maxiter xmin xmax ymin ymax) 
     (writexbm picture file) 
     (format t "File Written.") 
     0)) 

(main) 

Aunque el código no es muy LISP-ish (es que una palabra?) funciona. Gracias a todos los que se registró/comentado/respondió :)

+0

no puede publicar imágenes o varias URL porque es un miembro nuevo. Esta regla es simplemente reducir el spam. Edité tu publicación para ti – Jimmy

+0

¿Sabes que la generación del archivo xbm es correcta en la versión lisp? Quizás algunas pruebas unitarias serían apropiadas (es decir, dibujar un cuadrado y un círculo y ver si salen bien). –

+1

¿Qué sucede si haces algunos de tus números en doble flotante? También tenga en cuenta que los números complejos son parte de CL. – Brian

Respuesta

5

No estoy seguro de que esta parte es correcta:

 (setq tmpcplx (+ (* (* tmpreal tmpcplx) 2) cplx)) 
     (setq tmpreal (+ (- (* tmpreal tmpreal) (* tmpcplx tmpcplx)) 
      real)) 

Isn' t tempcplx se sobrescribe con su nuevo valor en la primera línea, lo que significa que la segunda línea usa el nuevo valor, no el original.

En la versión de Python que esté evitando este problema mediante el uso de TMPB:

tmpb = tmpcplx 
    tmpcplx = tmpreal*tmpcplx*2 
    tmpreal = tmpreal*tmpreal - tmpb*tmpb 
    tmpcplx += cplx 
    tmpreal += real 

Me parece la versión Lisp debe hacer algo similar, es decir, almacenar el valor original de tmpcplx primero, y utilizar esa tienda para el cálculo de tmpreal:

 (setq tmpb cplx) 
     (setq tmpcplx (+ (* (* tmpreal tmpcplx) 2) cplx)) 
     (setq tmpreal (+ (- (* tmpreal tmpreal) (* tmpb tmpb)) 
      real)) 
+3

Common Lisp tiene PSETF para este tipo de asignación paralela. – Svante

10

Algunas observaciones acerca de su código:

  • Mandelbrot: carece de las declaraciones, los cuadrados se calculan dos veces en el bucle

  • Mandelbrot: en el cómputo para TMPREAL está utilizando el nuevo valor de TMPCLX, no el anterior

  • No desea utilizar METHODS para establecer píxeles. LENTO.

  • FLOORDIV es uno de suelo o TRUNCATE (dependiendo de lo que desee) en Common Lisp, ver (piso 10 3)

  • declaraciones de tipo de uso

  • en writexbm No llame varias veces DATOS y ARRSIZE

  • setPixel, unsetpixel parece muy caro, de nuevo la eliminación de referencias repetidas ocasiones la estructura

  • extracción de Mandelbrot tiene una gran cantidad de r cálculos epeated que se pueden hacer una vez

  • Common Lisp tiene matrices 2D que simplifican el código

  • Common Lisp tiene números complejos, que también simplifican el código

  • un nombre de variable 'yo' no hace sentido en Common Lisp. Nombralo a lo que es.

En general, el código está lleno de residuos. Tiene poco sentido comparar su código, ya que está escrito en un estilo que afortunadamente nadie usa en Common Lisp. Common Lisp ha sido diseñado con la experiencia de un gran software matemático como Macsyma y permite escribir código matemático de forma directa (sin objetos, solo funciones sobre números, matrices, ...). Los mejores compiladores pueden aprovechar los tipos primitivos, las operaciones primitivas y las declaraciones de tipos. Por lo tanto, el estilo es diferente de lo que se podría escribir en Python (que normalmente es Python orientado a objetos o llamadas a algún código C) o Ruby. En código numérico pesado, generalmente no es una buena idea tener un despacho dinámico como con CLOS. Establecer píxeles en mapas de bits a través de llamadas CLOS en un LOOP ajustado es realmente algo que uno quiere evitar (a menos que sepa cómo optimizarlo).

Los mejores compiladores de Lisp compilarán las funciones numéricas para dirigir el código de máquina. Durante la compilación, dan pistas sobre qué operaciones son genéricas y no pueden optimizarse (hasta que el desarrollador agregue más información de tipo). El desarrollador también puede 'DESMONTAR' las funciones y verificar si el código es genérico o si realiza llamadas a funciones innecesarias. 'En Consing código numérico de ' "TIEMPO' proporciona información en tiempo de ejecución y también informa a los desarrolladores acerca de la cantidad de memoria' consed flota' es un problema de rendimiento habitual

Por lo tanto, para resumir:

  • si escribe código y cree que lo hace en diferentes idiomas, cuando el código es similar o tiene una estructura similar, este podría no ser el caso, a menos que realmente conozca ambos idiomas y ambas implementaciones de idioma.

  • Si escribe código en un idioma y lo transfiere en un estilo similar a otro idioma, puede perder un wh La cultura existente para escribir soluciones a este tipo de problemas de una manera diferente. Por ejemplo, uno puede escribir código en C++ en un estilo orientado a objetos y portarlo de una manera similar a FORTRAN. Pero nadie escribe dicho código en FORTRAN. Escrito en estilo FORTRAN, generalmente resultará en un código más rápido, especialmente dado que los compiladores están muy optimizados para el código idiomático de FORTRAN.

  • "cuando en Roma, hablar como los romanos"

Ejemplo:

en SetPixel hay una llamada a la (primera (dim auto)). ¿Por qué no hacer de ese valor una ranura en la estructura en primer lugar, en lugar de hacer un acceso a la lista todo el tiempo? Pero luego el valor es constante durante el cálculo. Aún así, la estructura se pasa y el valor se recupera todo el tiempo. ¿Por qué no simplemente obtener el valor fuera del ciclo principal y pasarlo directamente? En lugar de hacer múltiples cálculos de eso?

Para hacerte una idea de cómo se puede escribir el código (con declaraciones de tipo, bucles, números complejos, ...), aquí hay una versión ligeramente diferente del cálculo de mandelbrot.

El algoritmo de núcleo:

(defvar *num-x-cells* 1024) 
(defvar *num-y-cells* 1024) 
(defvar *depth* 60) 


(defun m (&key (left -1.5) (top -1.0) (right 0.5) (bottom 1.0) (depth *depth*)) 
    (declare (optimize (speed 3) (safety 0) (debug 0) (space 0))) 
    (loop with delta-x-cell float = (/ (- right left) *num-x-cells*) 
     and delta-y-cell float = (/ (- bottom top) *num-y-cells*) 
     and field = (make-array (list *num-x-cells* *num-y-cells*)) 
     for ix fixnum below *num-x-cells* 
     for x float = (+ (* (float ix) delta-x-cell) left) 
     do (loop for iy fixnum below *num-y-cells* 
       for y = (+ (* (float iy) delta-y-cell) top) 
       do (loop for i fixnum below depth 
          for z of-type complex = (complex x y) 
          then (+ (complex x y) (* z z)) 
          for exit = (> (+ (* (realpart z) (realpart z)) 
              (* (imagpart z) (imagpart z))) 
             4) 
          finally (setf (aref field ix iy) i) 
          until exit)) 
     finally (return field))) 

Por encima de función devuelve una matriz 2D de números.

Escribir un archivo xbm:

(defun writexbm (array pathname &key (black *depth*)) 
    (declare (fixnum black) 
      (optimize (speed 3) (safety 2) (debug 0) (space 0))) 
    (with-open-file (stream pathname :direction :output :if-exists :supersede) 
    (format stream "#define mandelbrot_width ~d~&" (array-dimension array 0)) 
    (format stream "#define mandelbrot_height ~d~&" (array-dimension array 1)) 
    (format stream "#define mandelbrot_x_hot 1~&") 
    (format stream "#define mandelbrot_y_hot 1~&") 
    (format stream "static char mandelbrot_bits[] = {") 
    (loop for j fixnum below (array-dimension array 1) do 
      (loop for i fixnum below (truncate (array-dimension array 0) 8) 
       for m fixnum = 0 then (mod (1+ m) 8) do 
       (when (zerop m) (terpri stream)) 
       (format stream "0x~2,'0x, " 
         (let ((v 0)) 
          (declare (fixnum v)) 
          (dotimes (k 8 v) 
          (declare (fixnum k)) 
          (setf v (logxor (ash (if (= (aref array 
                   (+ (* i 8) k) j) 
                 black) 
                1 0) 
               k) 
              v))))))) 
    (format stream "~&}~&"))) 

Por encima de función toma una matriz y una ruta de acceso y escribe la matriz como archivo XBM. Un número 'negro' será 'negro' y los otros números son 'blanco'

llamada

(writexbm (m) "/tmp/m.xbm") 
+2

Entiendo completamente su argumento "when in rome", pero antes decidí que tendría que escribir con un estilo que pudiera ser coherente en todos los idiomas, ya que si escribía al estilo de un cualquier resultado del lenguaje se invalidaría debido a mi dominio de C++ frente a otros idiomas. Si solo escribiera el código en el vacío, definitivamente usaría tu código. Pero el código original estaba (con mi lógica inversa) no escrito con la optimización en mente (más allá de mis propios sesgos). Obviamente eres más hábil en Lisp que yo, y trataré de estudiar tu código hasta que pueda entenderlo. ¡Gracias! –

+3

Ahora los resultados se invalidan, porque PIENSAS que tu código es similar o hace algo similar, pero de hecho no es así. El ejemplo a + b en C y (+ a b) en Lisp parece ser similar, pero no lo son. Lisp tiene por defecto un numérico genérico con fixnums, bignums, complex, ratios, floats, ... Esto se comporta muy diferente del código C, aunque las declaraciones parecen ser similares. –

+0

¿Cómo me aseguro de que el código se ejecute de la misma manera en 5 lenguajes de programación estilísticamente diferentes? Cada idioma tiene sus idiosincracias, y a + b y (+ a b) son deliberadamente diferentes. Todos los idiomas no son creados iguales. Las decisiones en el proceso de diseño cambian la eficiencia de un idioma. Tener un entorno de tiempo de ejecución con tipos dinámicos tendrá un impacto en la velocidad, y esa fue una decisión de diseño del lenguaje en sí. Mi intención no es trabajar con el idioma, sino tener el lenguaje en función de la tarea. Sí, es una mentalidad de procedimiento, pero no puedo cambiar los estilos Y garantizar la transparencia. –