Discussion:
[racket] Looking for better designs to learn principles.
Don Green
2015-03-12 18:25:21 UTC
Permalink
;Design A:
;Rating: 1 out of 10
;Poor because it uses set!
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))

(void (print-two '(1 2))) ;=> 12
;-------------------------
;Design B:
;Rating: 2 out of 10
;Better because it nests expressions to avoid using set!
;Poor because it less readable.
(define print-two
(lambda (f)
(print (first f))
(print (first (rest f)))
f))

(void (print-two '(1 2))) ;=> 12
When called in situations that allow one expression only, enclose call
within a 'begin' expression.
;-------------------------
;Design C:
;Rating: 3 out of 10
;Is this an even better design because it is more readable than nesting
expressions as in Design B above?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(void (print-two '(1 2))) ;=> 12
;-------------------------
My questions are:
"Can you recommend a better method?"
"Can you recommend a better method using 'define with lambda'?"
"Does your better method use a macro?"
"Does your better method use a thread-through macro?" If so, could you
please provide the definition of the thread-through macro.
THANKS!
Jos Koot
2015-03-12 19:17:26 UTC
Permalink
#lang racket

(define (print-two f) (print (car f)) (print (cadr f)))
(print-two '(1 2)); prints 12

(define (print-all f) (for-each print f))
(print-all '(1 2)); prints 12
(print-all '(1 2 3 4)); prints 1234

Best wishes, Jos Koot
_____

From: users [mailto:users-***@racket-lang.org] On Behalf Of Don Green
Sent: jueves, 12 de marzo de 2015 19:25
To: ***@racket-lang.org
Subject: [racket] Looking for better designs to learn principles.


;Design A:

;Rating: 1 out of 10
;Poor because it uses set!

(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))

(void (print-two '(1 2))) ;=> 12
;-------------------------

;Design B:

;Rating: 2 out of 10

;Better because it nests expressions to avoid using set!

;Poor because it less readable.
(define print-two
(lambda (f)
(print (first f))
(print (first (rest f)))
f))

(void (print-two '(1 2))) ;=> 12

When called in situations that allow one expression only, enclose call
within a 'begin' expression.

;-------------------------

;Design C:

;Rating: 3 out of 10

;Is this an even better design because it is more readable than nesting
expressions as in Design B above?

(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))

(void (print-two '(1 2))) ;=> 12
;-------------------------

My questions are:
"Can you recommend a better method?"

"Can you recommend a better method using 'define with lambda'?"
"Does your better method use a macro?"

"Does your better method use a thread-through macro?" If so, could you
please provide the definition of the thread-through macro.

THANKS!
Tony Garnock-Jones
2015-03-14 16:39:35 UTC
Permalink
How about

(define print-two
(match-lambda
[(list* a b rest)
(print a)
(print b)
rest]))

?
Post by Don Green
;Rating: 1 out of 10
;Poor because it uses set!
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
;-------------------------
;Rating: 2 out of 10
;Better because it nests expressions to avoid using set!
;Poor because it less readable.
(define print-two
(lambda (f)
(print (first f))
(print (first (rest f)))
f))
(void (print-two '(1 2))) ;=> 12
When called in situations that allow one expression only, enclose call
within a 'begin' expression.
;-------------------------
;Rating: 3 out of 10
;Is this an even better design because it is more readable than nesting
expressions as in Design B above?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(void (print-two '(1 2))) ;=> 12
;-------------------------
"Can you recommend a better method?"
"Can you recommend a better method using 'define with lambda'?"
"Does your better method use a macro?"
"Does your better method use a thread-through macro?" If so, could you
please provide the definition of the thread-through macro.
THANKS!
____________________
http://lists.racket-lang.org/users
____________________
Racket Users list:
http://lists.racket-lang.org/users
Sean Kanaley
2015-03-14 22:35:47 UTC
Permalink
If "thread-through macro" refers to "
http://www.greghendershott.com/2013/05/the-threading-macro.html" then I
recommend a functional alternative called "compose":

(define print/cdr
(match-lambda
[(cons x xs) (print x) xs]))

(define print-two
(compose print/cdr print/cdr))

The result is chained through naturally since the input and output type of
the lower level function are equal.

For any number of printings

(define (print-n n)
(for/fold ([print-n identity])
([i n])
(compose print/cdr print-n)))

(define print-two (print-n 2))

And for any number of anythings

(define (iterate f n)
(for/fold ([chain identity])
([i n])
(compose f chain)))

(define print-two (iterate print/cdr 2))
Post by Don Green
;Rating: 1 out of 10
;Poor because it uses set!
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
;-------------------------
;Rating: 2 out of 10
;Better because it nests expressions to avoid using set!
;Poor because it less readable.
(define print-two
(lambda (f)
(print (first f))
(print (first (rest f)))
f))
(void (print-two '(1 2))) ;=> 12
When called in situations that allow one expression only, enclose call
within a 'begin' expression.
;-------------------------
;Rating: 3 out of 10
;Is this an even better design because it is more readable than nesting
expressions as in Design B above?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(void (print-two '(1 2))) ;=> 12
;-------------------------
"Can you recommend a better method?"
"Can you recommend a better method using 'define with lambda'?"
"Does your better method use a macro?"
"Does your better method use a thread-through macro?" If so, could you
please provide the definition of the thread-through macro.
THANKS!
____________________
http://lists.racket-lang.org/users
Alexis King
2015-03-14 22:41:23 UTC
Permalink
There’s also the thrush function from the point-free package, which uses the argument order of the threading macro while providing the functional style of compose.

http://pkg-build.racket-lang.org/doc/point-free/index.html?q=thrush#%28def._%28%28lib._point-free%2Fmain..rkt%29._thrush%29%29 <http://pkg-build.racket-lang.org/doc/point-free/index.html?q=thrush#(def._((lib._point-free/main..rkt)._thrush))>
Post by Sean Kanaley
(define print/cdr
(match-lambda
[(cons x xs) (print x) xs]))
(define print-two
(compose print/cdr print/cdr))
The result is chained through naturally since the input and output type of the lower level function are equal.
For any number of printings
(define (print-n n)
(for/fold ([print-n identity])
([i n])
(compose print/cdr print-n)))
(define print-two (print-n 2))
And for any number of anythings
(define (iterate f n)
(for/fold ([chain identity])
([i n])
(compose f chain)))
(define print-two (iterate print/cdr 2))
;Rating: 1 out of 10
;Poor because it uses set!
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
;-------------------------
;Rating: 2 out of 10
;Better because it nests expressions to avoid using set!
;Poor because it less readable.
(define print-two
(lambda (f)
(print (first f))
(print (first (rest f)))
f))
(void (print-two '(1 2))) ;=> 12
When called in situations that allow one expression only, enclose call within a 'begin' expression.
;-------------------------
;Rating: 3 out of 10
;Is this an even better design because it is more readable than nesting expressions as in Design B above?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(void (print-two '(1 2))) ;=> 12
;-------------------------
"Can you recommend a better method?"
"Can you recommend a better method using 'define with lambda'?"
"Does your better method use a macro?"
"Does your better method use a thread-through macro?" If so, could you please provide the definition of the thread-through macro.
THANKS!
____________________
http://lists.racket-lang.org/users <http://lists.racket-lang.org/users>
____________________
http://lists.racket-lang.org/users
Sean Kanaley
2015-03-15 15:01:06 UTC
Permalink
Ah, I should've said that performance is not ideal with either compose (or
thrush), since they build the entire e.g. 10 million long function chain
before calling it, so tail-recursive variants below

(define (iterate f n x)
(for/fold ([x x])
([i n])
(f x)))

or with the thread-through thingy

(define (iterate f n x)
(for/fold ([x x])
([i n])
(~> x f)))

With 128 MB default, DrRacket even ran out of memory with my compose
variant. Sorry!
Post by Alexis King
There’s also the thrush function from the point-free package, which uses
the argument order of the threading macro while providing the functional
style of compose.
http://pkg-build.racket-lang.org/doc/point-free/index.html?q=thrush#%28def._%28%28lib._point-free%2Fmain..rkt%29._thrush%29%29
<http://pkg-build.racket-lang.org/doc/point-free/index.html?q=thrush#(def._((lib._point-free/main..rkt)._thrush))>
If "thread-through macro" refers to "
http://www.greghendershott.com/2013/05/the-threading-macro.html" then I
(define print/cdr
(match-lambda
[(cons x xs) (print x) xs]))
(define print-two
(compose print/cdr print/cdr))
The result is chained through naturally since the input and output type of
the lower level function are equal.
For any number of printings
(define (print-n n)
(for/fold ([print-n identity])
([i n])
(compose print/cdr print-n)))
(define print-two (print-n 2))
And for any number of anythings
(define (iterate f n)
(for/fold ([chain identity])
([i n])
(compose f chain)))
(define print-two (iterate print/cdr 2))
Post by Don Green
;Rating: 1 out of 10
;Poor because it uses set!
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
;-------------------------
;Rating: 2 out of 10
;Better because it nests expressions to avoid using set!
;Poor because it less readable.
(define print-two
(lambda (f)
(print (first f))
(print (first (rest f)))
f))
(void (print-two '(1 2))) ;=> 12
When called in situations that allow one expression only, enclose call
within a 'begin' expression.
;-------------------------
;Rating: 3 out of 10
;Is this an even better design because it is more readable than nesting
expressions as in Design B above?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(void (print-two '(1 2))) ;=> 12
;-------------------------
"Can you recommend a better method?"
"Can you recommend a better method using 'define with lambda'?"
"Does your better method use a macro?"
"Does your better method use a thread-through macro?" If so, could you
please provide the definition of the thread-through macro.
THANKS!
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
Continue reading on narkive:
Loading...