I don’t think this is true. Maybe let
or letrec
?
I was basing what I said on how define
gets expanded in an internal definitions context. It appears to expand to nested let
s, though it also expands to letrec
if the define
s bind functions that refer to one another.
Another example of define
surprising me. The following does not work: (define (foo bar)
(define bar (string-upcase bar))
bar)
but this does work: (define (foo bar)
(let ([bar (string-upcase bar)])
bar))
This is not contrived. I have a very complicated function, that I’m not quite ready to refactor. I need to upcase an argument, so I thought I could save some trouble by simply using (define foo (string-upcase foo))
at the top of the function, but it failed.
Again, the let
family have simply always worked as I expected, so I’m fine with a bit of rightward drift.
Wouldn’t it be nice if there’s no rightward drift, and the code works…
In (define x e)
the scope of x
includes e
. This is handy for defining recursive functions. It’s not so handy, when you have a let*
type of scenario. You sort of need an define*
.
Yes, but aesthetically, I think I still prefer: (let ([abc "def"]
[def 7.8]
[ghi 31416]
[jkl mno])
(use-these-variables ...))
more than: (define abc "def")
(define def 7.8)
(define ghi 31416)
(define jkl mno)
(use-these-variables ...)
Interesting. What are your reasons?
The former is prettier.
Notice the boiler plate of having the same word “define” specified over and over again. It’s the antithesis of Scheme for me.
I like internal define
for defining functions, but not variables.
I’m not gonna argue with that then :slightly_smiling_face:
But in Rhombus, it probably could look like:
let abc := "def"
let def := 7.8
...
or even:
abc := "def"
def := 7.8
...
would that help?
If I were to design one on S-exp now, I would make it look like:
{let abc := "def"}
...
I will continue to use #lang racket
if/when Rhombus is completed. I chose Racket, in part, due to the Scheme syntax.
let
is closer to ML for me, so I prefer it for that reason alone :slightly_smiling_face:
Is this not working b/c the define
is like let rec
in ML? i.e., you can create self-referential definitions, instead of using the old value?
nvm, @soegaard2 answered: https://racket.slack.com/archives/C09L257PY/p1609266408133300
Hi, Hazel, sorry I didn’t check this Slack yesterday. Glad to hear that you are working through LACI and enjoying it. I’m happy to take questions here or directly by email. Since you figured out the universe hierarchy, you probably also figured out that in the two-sort system, you have to make sure that for the Arrow case, the recursive synths have to produce a sort. But that’s about it.
Working through <git://github.com/zyrolasting/racket-koans.git>, having trouble with a contract exercise: ;; Read this carefully: Write a procedure `my-join` that joins at least
;; one integer together into a single string with an optional delimiter
;; character that defaults to a single blank space as the first argument.
;; Have a contract enforce these precise restrictions. Hint: You will
;; need 'case->'
(define/contract my-join
(case->
(-> char? integer? #:rest (listof integer?) string?)
(-> integer? #:rest (listof integer?) string?))
(let ([join (λ (c i is)
(string-join (map number->string (cons i is)) (string c)))])
(case-lambda
[(c i . is) (join c i is)]
[(i . is) (join #\space i is)])))
(let ([arity (procedure-arity my-join)])
(if
(and
(arity-at-least? arity)
(eqv? (arity-at-least-value arity) 1))
(begin
(check-equal? (my-join #\- 1 2 3) "1-2-3")
(check-equal? (my-join #\space 1 2 3) "1 2 3")
(check-equal? (my-join 1 2 3) "1 2 3")
(check-equal? (my-join #\space 1) "1")
(check-equal? (my-join 1) "1")
(check-exn (λ () (my-join #\?)))
(check-exn (λ () (my-join ",")))
(check-exn (λ () (my-join #\space "a" "b")))
(check-exn (λ () (my-join "," 0.1 9))))
(fail "Double check your signature of my-join")))
I get this error it seems because I cannot distinguish the case char int int*
from int int*
with just case->
/case-lambda
? my-join: contract violation
expected: char?
given: 1
in: the domain of
the 1st case of
(case->
(->
char?
integer?
#:rest
(listof integer?)
string?)
(->
integer?
#:rest
(listof integer?)
string?))
contract from: (definition my-join)
I will be doing some small rewrites to LACI in the next few weeks based on what I learned from my course offering this fall, and then I will add a new chapter on how to add holes to the predicate version of Proust (I’ve gotten as far as using unification to refine holes, the equivalent of the “apply” tactic in Coq or C-c C-r in Agda), with more discussion of things like implicits, placeholders, pattern matching, and user-defined datatypes.
How do you check whether you have a boolean true?
I guess anything is true except #f.
That’s what racket/bool seems to tell me: https://docs.racket-lang.org/reference/booleans.html
Only #t is a Boolean true. But everything else except #f is “truthy”. Opinions are divided on this.
@badkins I hit this kind of thing often too. The three idioms I see for this are: - using let
- using different names, like bar
and bar*
- using set!
let
solved the problem perfectly. Upon further analysis, it wasn’t that big of a deal. The function was inexcusably long, but most of it was internally defined helper functions, so the actual amount of code that needed to be w/in the let
wasn’t that much. I thought some of the helpers may have closed over the argument, but none of them did.
One could argue that this is sort of a problem with shadowing variables, as opposed to define
vs. let
.
Other languages will provide warnings when you’ve shadowed a variable, because it can be confusing to read code where the same identifier is used for different variables.
That’s an odd exercise. Looks to me like you have to decompose the argument list in an unusual way. The way I’m thinking about it, one of the cases would use (or/c char? integer?)
.