How to practically define a lot of things based on a condition in Scheme/Racket?
Asked Answered
S

2

6

I'm working in Racket but as far as I know this is the case in Scheme in general; you cannot do something like this because we are trying to define something in an expression context:

(if condition
    (define x "do a backflip")
    (define x "do a barrel roll"))

Now for this particular case I could do something like this instead:

(define x
  (if condition
      "do a backflip"
      "do a barrel roll"))

But if you have a lot of different things to define this gets really awful, because instead of

(if condition
    (begin (define x "do a backflip")
           (define y "awesome")
           (define z "shoot me"))
    (begin (define x "do a barrel roll")
           (define y "nice")
           (define z "give me sweet release")))

we get

(define x                                                                                                                                                                                                                                      
  (if condition
      "do a backflip"
      "do a barrel roll"))
(define y                                                                                                                                                                                                                                      
  (if condition
      "awesome"
      "nice"))
(define z                                                                                                                                                                                                                                      
  (if condition
      "shoot me"
      "give me sweet release"))

Which isn't as DRY as it could be, we are constantly repeating the test for condition. And the result is that if instead of testing for condition we want to check for other-condition, we have to make changes n times for n the amount of things being defined. Is there a better way to do this, and if so: How?

Syncopated answered 20/7, 2017 at 10:3 Comment(0)
D
5

Use define-values:

(define-values (x y z) (if condition
                           (values "do a backflip"    "awesome" "shoot me")
                           (values "do a barrel roll" "nice"    "give me sweet release")))
Divestiture answered 20/7, 2017 at 10:51 Comment(0)
A
4

If "a lot" is really large, you might want to use Racket's units.

First define a signature with all the variables you want to define:

(define-signature acro^ (x y z))

Then define units that contain the different sets of definitions:

(define-unit flippy@
  (import) (export acro^)
  (define x "do a backflip")
  (define y "awesome")
  (define z "shoot me"))

(define-unit rolly@
  (import) (export acro^)
  (define x "do a barrel roll")
  (define y "nice")
  (define z "give me sweet release"))

You can choose dynamically which unit do invoke and bind to the names in the signature:

(define-values/invoke-unit
  (if .... flippy@ rolly@)
  (import) (export acro^))

x
;; => either "do a backflip" or "do a barrel roll", depending on condition
Arabele answered 20/7, 2017 at 16:31 Comment(1)
What would be the advantage of this over define-values?Syncopated

© 2022 - 2024 — McMap. All rights reserved.