It looks like I should probably read Andrew’s dissertation as well.
with megaparsack, is there a way to balance parentheses?
something like (define balanced/p
(do (char/p #\()
(many/p balanced/p)
(char/p #\))))
like, have 0 to infinity copies of the parser within the parser
…turns out that’s the literal implementation
not without the original module’s permission, which it can grant in the form of #:unprotected-submodule
I do think of cons-lists as linked lists. Is that inadequate?
Not sure. The actual implementation in memory (at the time the course was taught at least), was slightly different from linked lists (according to the professor), so he said to not use the term linked list
So yeah
Actually I think I found the relevant spot in my course notes from that year
So what it’s saying is that say you have this: (define nums '(1 2 3))
(define five-lis (cons 5 nums))
Then five-lis
and nums
share the same list elements in memory
So if you call a function that mutates nums? Then five-lis
will mutate too?
But this isn’t a problem in Racket usually
Since things cannot be mutated
But, this is not true in something like C
So “linked lists” works differently in Racket and C
I think that was the main idea
Not really
(cons A B)
is really just:
x = malloc()
x->fst = A
x->snd = B
It’s the same
While it’s true that in Racket you cannot mutate things, that’s an additional restriction that you impose afterwards. The structure is still the same.
And note that if you use mutable cons (mcons
), then you can do everything that you can in C.
E.g., create a circular list.
And in Scheme, mutable cons is the regular variant of cons
.
So my Racket example converted to C would be like this right: cons *elem3 = malloc(sizeof(cons)); elem3->car = 3; elem3->cdr = NULL;
cons *elem2 = malloc(sizeof(cons)); elem2->car = 2; elem2->cdr = elem3;
cons *elem1 = malloc(sizeof(cons)); elem1->car = 1; elem1->cdr = elem2;
cons *nums = elem1;
cons *five = malloc(sizeof(cons)); five->car = 5; five->cdr = nums;
So calling a function that mutates nums
would also mutate five
Yes
yea
Yeah, mcons and Scheme cons do something other than the usual Racket cons that we usually used in that first year introductory course, but yeah
The idea that they were trying to convey was that pure cons
Racket type linked lists is usually not what we want in C
Sharing nodes is usually a bad idea
Bad side effects that we probably don’t want
It depends on what you want to do. You can totally create a persistent data structure in C. There’s nothing wrong with that.
In fact, it’s been used to avoid memory blowup in several applications
Persistent means immutable right?
hmm
Yeah, immutable.
So you can share data without having to copy the whole structure
Yeah I’m not familiar with KLEE or where the relevant code is, but I guess they use some sort of class/object interface and just don’t allow direct modifiction (and have setters and getters instead, only)?
I mean, not even setters then
If it’s immutable
Not everything is needed to be enforced by the language. You can just document that no one should modify it. But yes, having the language to enforce it for you is nice, because people do make mistakes.
Yeah
Haskell is based around that entire principle apparently
The language enforces immutability
(haven’t actually used Haskell but I am going to try and learn it over the next few weeks)
But yes, it is a myth that one can’t do pure functional programming in C
It can be done
Just requires some caution and patience and things
It is true that it isn’t enforced by the language
Just like functional programming is not enforced by Racket
set!
and things exist
But usually easy to avoid
I like how they explicitly mark them in Racket by using !
too lol
Question: Is it an accurate statement to say that arguments are passed by reference in Racket?
Seems like it with mcons
?
Wait…?
not sure
No. It’s pass by value, but you pass references around. Same for Java.
If it’s pass by reference, then you would expect:
(define (f x)
(set! x 1))
(define y 0)
(f y)
(println y)
to output 1, but it’s not.
??
(define lis (mcons "joe" '()))
(define (fun l)
(set-mcar! l "jojo"))
(fun lis)
(displayln lis)
This seems to output {jojo}
But yes, set!
seems to be doing something different
How is this?
Could you explain this: “It’s pass by value, but you pass references around. Same for Java.”?
Not familiar with Java at all
There are two types of mutation; variable mutation and structure mutation.
In Racket, you mutate variables by using set!
and mutate structure by using stuff like vector-set!
, hash-set!
, set-car!
, etc.
In, say, C, you mutate variables by <var> = ...
, and mutate structure by A[B] = ...
or A.B = ...
, etc.
And these are different
To use C as an example (since you seem to be familiar with it)
#include <stdio.h>
void f(int x) {
x = 2;
}
int main() {
int a = 1;
f(a);
printf("%d\n", a);
return 0;
}
This outputs 1
, because when you call f
, it passes the value of a
(1
) to f
, and f
makes a copy of 1
and put it in x
. So when you variable-mutate x
, a
is unaffected.
On the other hand, for
#include <stdio.h>
void f(int x[]) {
x[0] = 2;
}
int main() {
int arr[] = {1};
f(arr);
printf("%d\n", arr[0]);
return 0;
}
The content of arr
is its address. When you call f
, it passes the value of arr
(adddress of arr
) to f
, and f
makes a copy of this address and put it in x
. So when you structure-mutate x
, arr
is affected.
Racket is the same as C. It’s pass by value.
But when you pass objects to a function, it passes their addresses. Just like the arr
example.
Pass by reference is different. When you call f
, it doesn’t pass the value. Instead x
and a
become the “same” variable.
So any variable mutation to x
will affect a
.
Thank you for the example, it is much clearer now
So are references only for objects?
What is an “object”?
I gotta go now, sorry.
OK
I’m still not entirely clear, so I will type my questions here if anyone else knows though: • In Racket, things are passed by value according to @sorawee • But, for “objects”, alongside the value for the “object”, the reference (address in memory) is also passed. Is this statement true? What is an “object”? Is it passed if we call foo(lis)
, foo(1)
and also for foo(some-number-variable-name)
?
Clearly 1
does not have a reference, but I probably some-number-variable-name
and lis
(which is a list) both do (right?)
How do you know when the references are passed?
Again, not sure what happens in Java but is it a similar story there then?
in java everything is a reference except for primitives (int and such)
I’m more familiar with C++, but is this sort of related to lvalues (things that can be assigned a value, and thus, “mutated”)?
Obviously you can’t assign a value to "string"
and 42
i’m not familiar with c++’s rules either
(i probably should be familiar with c’s rules though)
Yeah, maybe what happens in Racket is that everything that can be assigned a value (things with a name?) are passed by value, but implicitly the reference is passed as well (wondering if someone can confirm)
Yeah, lvalue seems to be a fancy C++ term but it just refers to variable name, not anything fancy really
Things like primitives in Java would be called rvalues
I think
I think lvalue and rvalue are C, but things like glvalue are c++ only
I see
I think you are correct about the rvalues vs lvalues though
I find the concept quite confusing
Rust does a much better job at dealing with it i think
IIRC the only way to assign a value is to a mutable reference
I see
Like mcons
or hash
?
like box
sort of
Otherwise we can’t do it I guess
in rust reference is a type, so it doesn’t quite translate
it’s mostly like references in c++
Right
I don’t really use references that often, usually it’s pointer
Forgot that existed lol
haha
I don’t use c++ much, but i like to use references when i can
it makes my code a little neater
Haven’t really used boxes in Racket
I haven’t either. I sort of don’t get them
But things that are “objects” like mcons
or hash
seem to have set-foo!
usually, where foo is an “element”
As far as i can tell, their use is basically as a structural mutation wrapper
yeah
Yeah. I think I mostly get it. Two types of mutation. Variable and structure
Structures can be mutated within a function since their location in memory is also passed
Variables don’t have their locations in memory passed I guess then
They might?
But when you enter a function like (foo x)
, x
is just a local variable
if you assign that local variable to something else, the original stuff is gone, no matter where is was before
The original caller to that function doesn’t know anything about x
~i think i know where to read about this more in the manual~ nvm
Yeah I think this makes sense if you think about how functions are called in C
The caller stores everything it needs on it’s own stack frame
The callee just does it’s own thing
Unless a reference is passed, the callee and caller live on different worlds
I think the reference is only passed for “objects” in Racket
But I’m not sure what an “object” is though
Even I’m confused now. I think even if “objects” are passed, variable mutation won’t do anything to them
You need to go into their memory location, and modify their contents
idk
ah
From the guide page https://docs.racket-lang.org/guide/set_.html?q=mutation#%28part._using-set%21%29 > The use of mutable values, such as vectors and hash tables, raises fewer suspicions about the style of a program than using set!
directly. Nevertheless, simply replacing set!
s in a program with vector-set!
s obviously does not improve the style of the program.
So think there is a notion of “mutable values” and normal (immutable) values
I think this is the same as the rust concept of “interior mutability”
Hmm
When it comes to hash tables, there really are a few types
The one I usually use is mutable
The other category is immutable
So things like set-hash!
will only work for mutable ones
I guess I break functional programming paradigms when I use mutable hash tables
Didn’t realize
Yep
make-hash
makes a mutable hash
the naming conventions there are confusing to me
because hash
makes an immutable map, but make-hash
makes a mutable map so i need to use make-immutable-hash
if i want an immutable hash, but constructing it with the make-
conventions
I think you can pass a mutable hash to make-immutable-hash
and it will give you an immutable hash
Yeah, it is slightly confusing