[racket] thread-through ?

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Sat Feb 21 10:17:07 EST 2015

Here are some realistic, non-contrived examples where I use macros like thread-through [called build-scene] a lot: 

;; Image Number Number -> Image
;; (x0,y0) is where we want to add a branch 
(define (fork s0 x0 y0)
  (define xB (x-B x0))
  (define yB (y-B y0))
  (define xC (x-C x0))
  (define yC (y-C y0))
  [define A (interior)]
  [define B (leaf)]
  [define C (leaf)]
  (build-scene 
   scene s0
   (pin-over scene x0 y0 A)
   (pin-over scene xB yB B)
   (pin-over scene xC yC C)
   (pin-line scene A ct-find B cb-find)
   (pin-line scene A ct-find C cb-find)))

This is an excerpt from HtDP/2e's source code. The function adds a 'fork' to a game tree. I use the function to build sample trees, which then get spliced into the book: 

;; -> Image 
;; binary trees of n levels 
(define (3-level-tree)
  (define height 225)
  (define y0 (- height 25))
  (define xB (x-B 90))
  (define yB (y-B y0))
  (define xC (x-C xB))
  (define yC (y-C yB))
  
  (build-scene 
   s (rectangle (* 2 width) height)
   (fork s 90 y0)
   (fork s xB yB)
   (fork s xC yC)))










On Feb 20, 2015, at 11:11 PM, Alexander D. Knauth wrote:

> 
> On Feb 20, 2015, at 10:45 PM, Alexander D. Knauth <alexander at knauth.org> wrote:
> 
>> 
>> On Feb 20, 2015, at 6:56 PM, Don Green <infodeveloperdon at gmail.com> wrote:
>> 
>>> I looked in racket documentation and discussion archives for a thread-through function as illustrated below but without success.
>>> Any suggestions where I should look? OR please explain that line below only.
>>> Looks like it is declaring thread-safe variables x e and any others I care to list.  Is that correct?
>>> 
>>> ;Use a macro:
>>> (thread-through x e …)
>>> ==
>>> (let* ([x e] …) x) 
>>> ;——————————
>> 
>> If you have this macro definition:
>> 
>> (define-simple-macro
>> (thread-through x e ...)
>> (let* ([x e] ...) x))
> 
> I probably should start with a simpler example.  This:
> (thread-through x 1 (add1 x))
> Will evaluate to the same thing as:
> (add1 1)
> This:
> (thread-through x 1 (add1 x) (number->string x))
> Will evaluate to the same thing as:
> (number->string (add1 1))
> This:
> (thread-through x ‘foo (symbol->string x) (string->list x) (reverse x) (list->string x))
> Will evaluate to the same thing as:
> (list->string (reverse (string->list (symbol->string ‘foo))))
> 
> And If you wanted to do something like this:
> (map first
>     (sort (map (λ (x) (list x (modulo (expt 11 x) 13)))
>                '(0 1 2 3 4 5 6 7 8 9 10))
>           < #:key second))
> 
>> 
>> Then you can do things like this: (contrived example)
>> 
>> (thread-through
>> lst '(0 1 2 3 4 5 6 7 8 9 10)
>> (map (λ (x) (list x (modulo (expt 11 x) 13))) lst)
>> (sort lst < #:key second)
>> (map first lst)) ; '(0 7 4 2 3 5 9 8 10 1 6)
> 
> And if you wanted to do something like this:
> (let ([tree 0])
>  (set! tree (list tree 1 tree))
>  (set! tree (list tree 2 tree))
>  (set! tree (list tree 3 tree))
>  tree)
> 
>> 
>> And this: (adapted from an example in http://docs.racket-lang.org/guide/set_.html#%28part._using-set%21%29)
>> 
>> (thread-through
>> tree 0 
>> (list tree 1 tree)
>> (list tree 2 tree)
>> (list tree 3 tree)) ; '(((0 1 0) 2 (0 1 0)) 3 ((0 1 0) 2 (0 1 0)))
> 
> Or if you wanted to do something like this:
> (string->bytes/utf-8 (number->string (bytes-length #”foobar”) 16))
> 
>> 
>> And this: (adapted from http://pkg-build.racket-lang.org/doc/rackjure/index.html#%28part._.Threading_macros%29)
>> 
>> (thread-through
>> x #"foobar"
>> (bytes-length x)
>> (number->string x 16)
>> (string->bytes/utf-8 x)) ; #"6"
>> 
>> It has nothing to do with thread-safe variables.
>> It is similar in spirit to ~> from rackjure, or -> from clojure, or ~> or thrush+ from point-free, if you want to look at those.  
>> 
>> 
>> 
>> ____________________
>> Racket Users list:
>> http://lists.racket-lang.org/users
> 
> 
> ____________________
>  Racket Users list:
>  http://lists.racket-lang.org/users



Posted on the users mailing list.