@aymano.osman do you use syntax-parse
? I find that helps me write simpler and more correct macros a lot
Yes syntax-parse
eliminates a huge source of bugs in destructuring input syntax.
The syntax-rules
, syntax-case
, and define-syntax-rule
forms really ought to have their reference docs updated to suggest using syntax-parse
instead.
mental todo list note
Have the portions of the Guide about macros been rewritten for syntax-parse
?
So, real new to racket (and lisp in general), with probably less than ten hours under my belt. I started with beautifulracket, but paused to learn a little more about syntax and structure.
So now I’m going through https://github.com/zyrolasting/racket-koans to do just that. Working through https://github.com/zyrolasting/racket-koans/blob/master/koans/procedures.rkt#L74 - I’ve found myself a little stuck on how to write the contract for this. Here’s my contract for my-joiner
so far: (define/contract (my-join delimiter . numbers)
(case->
[-> integer? #:rest (listof integer?) string?]
[-> string? #:rest (listof integer?) string?])
...
based on the tests, I’ll be given an arbitrary number of parameters, so I can use a rest-id to separate a possible delimiter, then handle mapping/joining based on that first parameter. The example suggests that I need case->
, but I just don’t think I understand how to use it here. What I’ve got matches based on the number of arguments, it seems. Not the types of values.
If someone can give me a nudge in the right direction (either on contracts, or maybe just my approach to the problem), that’d be amazing.
Contracts are not types. Checking the number of arguments is the right approach imo
yeah, just read through case-lambda. I think I’ve been conflating contracts and pattern matching.
but you have to actually distinguish the cases for different # of arguments in the contract
in the code you pasted, the two cases overlapped
Gotcha. So in the contract, if I wanted to allow the first argument to be an integer, string, or char, I could do: [-> (first-or/c integer? string? char?) #:rest (listof integer?) string?]
(I mean, maybe there’s a better contract, but that’s the gist?)
yes, but this contract let (my-join #\space)
passes without raising an error
I would try to split the cases into: - A contract for 1 argument - A contract for 2 or more arguments
ah, sure - I’d want a case-> that handles a single arg, and expects a number.
right
so this turns into: - (-> ? ?result)
- (-> ? ? #:rest ?rest ?result)
and the two are combined via case->
cool.
Thanks a bunch, this clears a lot up!
Also for the first argument you can use or/c