@radchenko.maxim has joined the channel
I’d like to bind two/multiple ids in different ways depending upon a condition. Is define-values the most common way to do this?
What I mean is something like: (define-values (new-x new-y)
(if baz
(values (foo x)
y)
(values x
(bar y)))
I often end up having two different paths of an if which do the exact same thing but with the bindings for the names being different. It feels wrong to have two near-identical paths, and so I often find myself doing the above and then I can just have one path. Here’s the actual code: (define (parse-program the-program)
(for/fold ([pc 0] [lines '()] [labels (hash)]
#:result (values pc lines labels))
([line the-program])
(define-values (label op rands)
(destructure-line line))
(define-values (new-labels new-lines)
(if label
(values (hash-set labels label pc)
(cons (strip-label line) lines))
(values labels
(cons line lines))))
(values (+ pc (op-length op))
new-lines
new-labels)))
If I didn’t have the weird define-values, I’d have two near-identical paths to an if: (if label
(values (+ pc (op-length op))
(cons (strip-label line) lines)
(hash-set labels label pc))
(values (+ pc (op-length op))
(cons line lines)
labels))
Perhaps others just prefer the multi-path version? I’ve come across this situation a few times in different pieces of code. I initially thought that’s what Clojure’s if-let would do, but it’s unrelated. Basically, a common body with the bindings based on a condition.
@sydney.lambda I think that’s a sign that you’re using values
to group together things that ought to go together in a struct
of some sort, so you can name the individual pieces and define functions that operate on the group of values as a unit
In your example, adding a definition for (struct program (counter lines labels))
would let you give names to some of the operations you’re doing. For example, the initial values you’ve chosen for the fold seem to represent an empty program containing nothing. So you could write (define empty-program (program 0 '() (hash))
to make that explicit in your fold, giving you (for/fold ([program empty-program]) ...)
adding another (struct program-line (label operator operands))
type for destructure-line
to return would let you put the loop body into a (program-add-line prog line)
function accepting a program?
and a program-line?
, then returning a new program?
this would make your loop look like this: (for/fold ([program empty-program])
([line the-program])
(program-add-line program (destructure-line line)))
Just to clarify, the programs look like this: (define the-program
'(( LDA $00 )
( BEQ NOTZERO)
( LDX $01 )
(NOTZERO: LDA $23 )))
and all I’m really doing is: * stripping the labels from any lines which have them (NOTZERO: for example) * incrementing the program counter based on the instruction * adding these labels to a map of (label . program-counter)
Perhaps I’m just over-complicating this in general?
I should definitely be using structs though.