Is there any convenient way to get the name of the procedure. For example: (define (do-some-test func)
(printf "do-test: = ~v\n" func))
(do-some-test func) This return >>do-test: = #<procedure:try-item> It doesn’t looks nice, imo… I hope to get “try-item” directly.
@franci.dainese Great! Very thank!
If I have two values and I want to use a container to pack them, should I use cons or list? For example, (cons 1 2)
>> '(1 . 2)
(list 1 2)
>> '(1 2) If values are primitive, cons seems better than list. Because cons can only contain two values, it is more clear. In Haskell, it means a pair.
But if values are not primitive: (cons (list 1 2) (list 3 4))
>> '((1 2) 3 4) <--- it is bad.
(list (list 1 2) (list 3 4))
>> '((1 2) (3 4)) In this case, list seems better.
But if you use list, you can no longer use car and cdr to get the two projections. (car (cons (list 1 2) (list 3 4)))
(cdr (cons (list 1 2) (list 3 4)))
>> '(1 2)
>> '(3 4)
(car (list (list 1 2) (list 3 4)))
(cdr (list (list 1 2) (list 3 4)))
>> '(1 2)
>> '((3 4)) <---- it is bad. So when we need a container to pack values, which constructor should I use? Is there something like Haskell’s pair or tuple in Racket? Thanks.
PS: There is another way, i.e. values. But values seems not be suitable as a container, because it cannot be nested.
Depends on your use case. Is this an “internal transfer of values”, then either would do (maybe use vector). If the two values are to be used “externally” then I suggest making a struct to hold the two values.
If you use a list, you can use first and second instead of car and cdr.
Haskell’s pair is the same as Racket cons.
But Haskell’s pair is different from list.
In Racket (list 1 2) is short for (cons 1 (cons 2 empty)). I think Haskell works the same?
In Haskell, cons is just a constructor of List.
It is different from Pair.
I think first and second is good, thanks.
Maybe this is why Racket provide these two functions.
In Haskell cons is : and 1:2:[] is the same as [1,2,3]. In Racket it is (cons 1 (cons 2 empty)) and (list 1 2 3).
Yes, but what I want is Pair, not Cons. I means (,)
Since a list is build of pairs (cons-cells) the functions first and second are almost the same as (car xs) and (car (cdr xs)).
It seems Racket does not provide pair constructor. Racket mix list and pair.
I think a 2-element vector is what is closest to a Pair.
(I am so used to Racket - I didn’t get that Pair and Cons were different the first time I read your comment …)
Does vector can be pattern matching? and it seems no provide first or second function?
Pattern matching works for vectors. There is (vector-ref v 0) and (vector-ref v 1). If you need to use them often, define little helper functions.
imo, if base-library does not provide this, then it means the pl designer does not recommend you to use it in that way.
This is why I think list still is a good solution, because it provide me first and second. This may be to fix the mixing issue of cons and list.
I agree that a list is a good solution,
If you happen to need “tuples” at a later time, have vectors in mind.
Keep in mind that there’s a difference between your ideal pair/fst/snd and list/first/second. The first approach only needs to allocate two cells to hold references to both elements. The second approach needs to allocate four cells. Of course, this won’t matter if you don’t need very high performance program (and if you do need a very high performance program, Racket is probably a poor choice anyway).
cons/car/cdr would be more similar to pair/fst/snd in this sense. It allocates only two cells.
When you said “it is bad”, note that it’s just the issue with printing. The printing simply doesn’t satisfy your preference. But there’s nothing wrong per se.
@sorawee Why > The first approach only needs to allocate two cells to hold references to both elements. > The second approach needs to allocate four cells. What do you mean by cells?
This diagram shows (list 1 2 3):
It shows three pairs which each has two cells.
This shows (vector 1 2 3):
So in the above diagrams (list 1 2 3) needs 6 cells, whereas (vector 1 2 3) needs 3 cells (this is talking about cells due to the container itself)
(cons 1 2) would be similar to (vector 1 2). They both use only 2 cells.
Thanks @sorawee. I know what you mean.
> When you said “it is bad”, note that it’s just the issue with printing. The printing simply doesn’t satisfy your preference. But there’s nothing wrong per se. (edited) Yes, that because Racket’s no provide a tag at the top of the cons and list. It would be nice, if Racket’s base library can provide some thing like (struct Pair (fst snd)
#:transparent)
If you prefer, you can install the rebellion package and use https://docs.racket-lang.org/rebellion/Pairs.html instead.
If you’re not writing generic code, I also suggest making your own named types instead of using semantics-free containers like pairs. Tuple types (https://docs.racket-lang.org/rebellion/Tuple_Types.html) and record types (https://docs.racket-lang.org/rebellion/Record_Types.html) are good for that.
Is this a correct way to write imperative style code in racket? For example, (define (do-step-1)
(printf "do-step-1\n"))
(define (do-step-2)
(printf "do-step-2\n"))
(define (do-step-3)
(printf "do-step-3\n"))
(define (do-something)
(let ((_ (do-step-1))
(v (do-step-2))
(_ (do-step-3))
)
v))
(do-something) But compile error: let: duplicate identifier I must to rename the _ to __ to fix it.
If I have a multi-line statements, do I need to rename all? __ ___ ____ and so on.
Why don’t you just write:
(define (do-something)
(do-step-1)
(define v (do-step-2))
(do-step-3)
v)
As a bonus:
(define (do-something)
(do-step-1)
(begin0 (do-step-2) (do-step-3)))
will return the value of (do-step-2) after evaluating both (do-step-2) and (do-step-3)
Another way is to use let*, which allows you to shadow existing variables
(define (do-something)
(let* ([_ (do-step-1)]
[v (do-step-2)]
[_ (do-step-3)])
v))
That means, racket do not hoisting internal define?
In some language, if you define (define (do-something)
(do-step-1)
(define v (do-step-2))
(do-step-3)
v) That exactly means: (define (do-something)
(define v (do-step-2))
(do-step-1)
(do-step-3)
v)
Nope. It won’t be rewritten to the latter
Thanks @sorawee, i think i will use let* solution. I usually use internal define to define a function instead of value.
Sure, that works. Note that let* makes your code drifted rightward a little bit, so I personally would prefer the first approach. The style guide also encourages the use of internal definition: https://docs.racket-lang.org/style/Choosing_the_Right_Construct.html#%28part._.Definitions%29
Alternative solution: (define (do-something)
(do-step-1)
(let ([v (do-step-2)])
(do-step-3)
v))
@sorawee Thanks, this guide is good!
But I still think let* is better, because mutually recursive scope is unnecessary here. For example, in other imperative language, like C or Java func print-two (f)
print (first (f));
var f = rest (f); <-----this f in rest should be paramter f instead of var f
print (first (f));
var f = rest f;
return f;
end It is more like let* version.
Sure, in that case, let* is the right construct to use.
I agree that rightward drift is a negative, but for me, semantics are more important than that, and I often want let semantics over define. Subjectively I prefer let style also, but if I contribute to Racket code, I’ll endeavor to follow the guide :slightly_smiling_face:
When I find my code drifting “too far” to the right, it’s often a sign I need to refactor anyway.
Relevant: my proposal to bring let* semantics into internal definition: https://github.com/racket/rhombus-brainstorming/issues/46
This feature is very suitable for debugging.
I have a question about null and '(), see this example: (define (test-match xs)
(match xs
[(list n1 null) (printf "case1 ~v\n" n1)] ;; <--------- see here I use null in pattern
[(list #f n2) (printf "case2 ~v\n" n2)]
[(list _ n3) (printf "case3 ~v\n" n3)]))
(test-match (list 99 null))
(test-match (list #f (list 1 2 3)))
(test-match (list 55 (list 1 2)))
>> case1 99
>> case1 #f
>> case1 55 When I use null in the pattern, it match all 3 case. i.e. print “case1” 3 times? This not what I want.
But if I modify the code to: (define (test-match xs)
(match xs
[(list n1 '()) (printf "case1 ~v\n" n1)] ;; <--------- see here, now I use '() in pattern
[(list #f n2) (printf "case2 ~v\n" n2)]
[(list _ n3) (printf "case3 ~v\n" n3)]))
(test-match (list 99 null))
(test-match (list #f (list 1 2 3)))
(test-match (list 55 (list 1 2)))
>> case1 99
>> case2 '(1 2 3)
>> case3 '(1 2) The result is correct.
Why? What’s the difference between null and '()? Can I use null in pattern match? Thanks.
If you type null in the repl, the result is printed as '().
So null is an identifier bound to the value “the empty list”.
What’s the difference between null and '()?
In comparison '() is literal syntax that evaluates to the empty list.
This implies that (eq? null '()) is true.
In short, null is simply a name for ’().
So they are the same thing.
Why the behavior are different?
Sometimes it is convenient to use literal syntax sometimes it is nice to use an identifier.
But when to use literal syntax, and when to use identifier?
Most people use ’()
In HtDP they use empty.
This is case, the behavior are completely different.
Same thing, but a better name than null.
Ah!
That’s because case doesn’t evaluate the left hand sides.
see https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._null%29%29 null is also empty list.
In (case 42 [(null) "foo"]) 42 will be compared to the symbol ’null
Null is not an empty list. It is an identifier, which is usually bound to the empty list.
Oh, I found that, null is a bound variable in the pattern match
(define (test-match2 xs)
(match xs
[(list n1 null) (printf "case1 ~v ~v\n" n1 null)]
[(list #f n2) (printf "case2 ~v\n" n2)]
[(list _ n3) (printf "case3 ~v\n" n3)]))
(test-match2 (list 99 null))
(test-match2 (list #f (list 1 2 3)))
(test-match2 (list 55 (list 1 2)))
>> case1 99 '()
>> case1 #f '(1 2 3)
>> case1 55 '(1 2) I can use null as a variable…
Yes. In Racket (and Scheme) there are no reserved keywords.
null be shadowed.
I understand, thanks @soegaard2 .
I think I should delete all null in my code and use '() instead. null seems not useful.
I really like https://docs.racket-lang.org/debug/index.html for debugging. You don’t need to wrap parentheses or remove them. Just put #R.
Also, I’m not aware of any language that rewrites in that way. It looks really unintuitive.
Languages like JS do have hoisting, but it does something like this:
(define (do-something)
(define v undefined)
(do-step-1)
(set! v (do-step-2))
(do-step-3)
v)
I think HtDP 2 switched to use '() instead
please use define instead of any of the let variants, being explicit about whether you want mutually recursive or nested scopes is all pain for no gain
it has no optimization benefits and makes it harder to read the structure of control flow
@chansey97 when you want to pattern match on a constant like null, you can also use the == pattern (match xs
[(== null) ...]) For the empty list I would just use '(), but for other kinds of constants I use ==.