Doge meme generator in Racket I wrote a doge meme generator in racket some time ago, mainly as a joke, and I would like some criticism about the general style and what could be improved. 

Here is how the program output looks : 



plainDoge.jpg refers to a plain image for the doge meme (700 * 525)

#lang racket
(require racket/gui
         racket/draw)

;keywords definitions
;TODO random capitalisation for first letter
(define doge-keywords
  '("such" "much" "so" "very"))
(define wow
  "Wow")

(define user-keywords
  '())
(define colors
  '("red" "magenta" "blue" "green" "yellow" "cyan" "white"))

(define (random-member my-list)
  ;gives a random member from a list
  (car
   (shuffle my-list)))

(define (make-sentence keyword)
  ;make a sentence 
  (string-append
   (random-member doge-keywords)
   " "
   keyword))

;TODO add max count
(define (make-sentences my-list)
  ;make a list of sentences
  (if (null? my-list)
      ;return a list containing this message
      '()
      ;else
      (cons wow 
            (map make-sentence
                 (shuffle my-list)))))

;frame
(define (create-parent-frame)
  (new frame%
       [label "racket-doge"]
       [width 700]
       [height 600]
       [style (list 'no-resize-border)]))

;canvas
(define (main-canvas parent-frame to-draw)
  (new canvas% [parent parent-frame]
       [min-height 500]
       [paint-callback
        (lambda (canvas dc)
          (send dc draw-bitmap to-draw 0 0))]))

;horiz panel
(define (create-horiz-panel parent-frame)
  (new horizontal-panel% [parent parent-frame]))

;font management
(define (set-font my-dc)
  (send my-dc set-font
        (make-font #:size (+ 20 (random 5))
                   #:family 'decorative
                   #:face "Comic Sans MS"
                   #:weight 'bold)))

;draw on doge
(define (draw-text-with-keywords kwd my-dc) 
  ;draw the text on my-dc
  (for-each
   (lambda (kw)
     (set-font my-dc)
     (send my-dc set-text-foreground (random-member colors))
     (send my-dc draw-text kw (random 700) (random 500)))
   (make-sentences kwd)))

;text edit
(define (create-user-entries horiz-panel)
  (new text-field%
       ;[enabled #f]
       [label "user-keywords :"]
       [init-value (string-join user-keywords ", ")]
       [parent horiz-panel]))

(define (parse-user-input user-entries)
  (string-split (send user-entries get-value) ", "))

;buttons
(define (gen-again-but horiz-panel user-entries my-dc p-frame)
  (new button% [label "Wow !"]
       ;generate again
       [parent horiz-panel]
       ;[enabled #f]
       [callback
        (lambda (b e)
          (send my-dc draw-bitmap (read-bitmap "plainDoge.jpg") 0 0)
          (draw-text-with-keywords
           (parse-user-input user-entries) my-dc)
          (send p-frame refresh))]))

(define (save-but doge horiz-panel)
  (new button% [label "Save"]
       ;Save the bitmap to a file
       [parent horiz-panel]
       [callback
        (lambda (b e)
          (send doge save-file
                "./generated_doge.png"
                'png))]))


;let's make the GUI and run the whole program
(define (make-gui)
  (let
      ([p-frame (create-parent-frame)])
    (let
        ([doge (read-bitmap "plainDoge.jpg")])
      (main-canvas p-frame doge)
      (let
          ([horiz-panel (create-horiz-panel p-frame)])
        ;let's create a drawing context and draw on it
        (let
            ([my-dc (new bitmap-dc% [bitmap doge])])
          (let
              ([user-entries (create-user-entries horiz-panel)]) 
            (draw-text-with-keywords
             (parse-user-input user-entries) my-dc)
            (gen-again-but horiz-panel user-entries my-dc p-frame)
            (save-but doge horiz-panel))))) 
    (send p-frame show #t)))

(make-gui)
There's lots of indentation that should be on a single line instead.
Including most of the lets.  There's also no reason to keep nesting
lets when you can just add additional definitions in a single let.
E.g. for make-gui it's entirely feasible just to have a single let
instead of four.

The save-but function doesn't need "./" in there, that's already
what will happen there's no additional path specified.

The bitmap should be only read once from disk; the additional read when
pressing the button is not necessary.  Hard coding the 700x500
dimensions into the code is also something that could be fixed by
querying the image (or the thing it's drawing on) for its size instead,
making it way more flexible in the process.  You should probably also
add a way to specify the output (and input) filename while you're at it.

random-member is not efficient, see
Rosetta Code,
i.e. it should be something like (list-ref my-list (random (length my-list))) instead, while not shuffling the entire list.

Otherwise I don't see too much to complain about; the variable names
could be more descriptive (save-but) and less truncated (horiz),
also the overuse of my- is a bit annoying (by which I mean that the
prefix doesn't provide the reader with any additional information).