radchenko.maxim
2019-7-13 19:19:37

@radchenko.maxim has joined the channel


sydney.lambda
2019-7-14 03:52:04

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.


notjack
2019-7-14 05:05:04

@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


notjack
2019-7-14 05:08:50

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]) ...)


notjack
2019-7-14 05:10:54

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?


notjack
2019-7-14 05:13:39

this would make your loop look like this: (for/fold ([program empty-program]) ([line the-program]) (program-add-line program (destructure-line line)))


sydney.lambda
2019-7-14 05:25:24

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)


sydney.lambda
2019-7-14 05:26:59

Perhaps I’m just over-complicating this in general?


sydney.lambda
2019-7-14 05:35:43

I should definitely be using structs though.