check-exn won’t tell you the error location when the exn-predicate return #f? See this example: (struct exn:fail:task ())
(struct exn:fail:task-2 ())
(define (task-always-fail)
(raise (exn:fail:task)))
(check-exn exn:fail:task-2? (λ () (task-always-fail))) As you see, the (task-always-fail) raise a wrong exception. Yes, this test failed, but it does not tell you where is wrong, no location information…(e.g. line number) It just says test-suite-2 > my-test-suite > Unnamed test
ERROR
A value other than an exception was raised: #<exn:fail:task> Is this is a rackunit’s bug?
When you create your own exn:fail:..., you should inherit the struct from exn:fail
FWIW (struct exn:fail:task exn:fail ())
@sorawee @soegaard2 Thank you, it works!
Sorry, I am a newbie for Racket. About exception, I have a question: I am writing a library. If some interface of this library needs to throw an exception to user (represent possibility to failure, like Maybe), which exn should I inherit?
For example, (struct exn:fail:task exn:fail ()) vs (struct exn:fail:task exn ())
Actually, if you wanna show this exception to user (who is not a programmer), then you should inherit exn:fail:user
@sorawee I means user of library. He is a programmer.:sweat_smile:
then exn:fail
In particular, there are two kinds of exn: exn:fail and exn:break
exn:break is what you get when you ctrl+c
What do you mean by ctrl+c? This keyword is copy, I am a windows user.
Had to Google: ctrl+break on Windows. It sends a break signal to the running process.
I understand, thanks @sorawee and @soegaard2!
Ctrl+c ought to work in DOS though…
So yeah, when you use with-handler (try..catch in other languages), you usually don’t want to intercept exn:break. So people will usually catch exn:fail
If you inherit from exn, then those with-handler will not work.
So inherit from exn:fail is the right way
Now I inherit from exn:fail , but I want to wrap a value in it: (struct exn:fail:task exn:fail (error-code))
(exn:fail:task 100) ; <---- why this failed?
; exn:fail:task: arity mismatch;
; the expected number of arguments does not match the given number
; expected: 3
; given: 1
exn:fail has exn as its super type.
And exn is defined as: (struct exn (message continuation-marks)
So your exn:fail:task needs three arguments: message, continuation-marks and error-code
Something like: (exn:fail:task "an error occurred" (current-continuation-marks) 42)
Thanks @soegaard2 I just found if in the raise, there is no need to fill these additional arguments.
—Edited:— This is wrong. It does not be filled these additional arguments automatically. You must be fill it manually. See comments below.
?
Can I pattern match a exception? (define (task-always-fail)
(raise (exn:fail:task 100)))
(check-exn (match? (exn:fail:task _ _ 100)) (λ () (task-always-fail)))
But failed.
PS: I found the match? from https://github.com/racket/racket/issues/1690 It’s good, so I copy paste it. (btw, I dont know why match? are not in the base library)
I think (task-always-fail) throws an “wrong number of arguments” exception.
So it doesn’t match the exn:fail:task
I did some experiments: (check-exn (lambda (e)
(printf "the e is ~v\n" e)
#t)
(λ () (task-always-fail))) The printf’s result is > (exn:fail:contract:arity “exn:fail:task: arity mismatch;\n the expected number of arguments does not match the given number\n expected: 3\n given: 1\n arguments…:\n 100” #<continuation-mark-set>)
You do need continuation marks and message
Yes, it works perfectly now, thanks again!
(define (task-always-fail)
(raise (exn:fail:task "an error occurred" (current-continuation-marks) 100)))
(check-exn (match? (exn:fail:task _ _ 100)) (λ () (task-always-fail))) ; passed
(check-exn (match? (exn:fail:task _ _ 99)) (λ () (task-always-fail))) ; failure (and error location appeared)
btw, I think match? is very useful, it should be added to base library :grinning:
Is there way to make a list in quote?
Backgound: I am writing a parser for s-expr by Racket. (ps: not practical programming, just for fun:grin:) Everything is OK, except that I don’t how to process quote. For example, suppose I want to parse '(1 2 3) (parse try-s-expr (string->list "'(1 2 3)")) I have been able to parse this '(1 2 3) to (s-quote (1 2 3)), where s-quote is my AST node. My question is how to make this inner list (1 2 3) to '(1 2 3? I have read https://docs.racket-lang.org/guide/quote.html, but the quote is a special form, so it is not suitable here.
I’m sorry, I just said “s-quote is my AST node” was actually a lie, because I want to use lisp homoiconicity, i.e. using Racket’s underlying structure as my AST node (actually, there is no custom AST node at all). But I hope you can understand what I mean…:worried: Thanks.
The reader turns ’(1 2 3) into (quote (1 2 3))
It’s the printer that prints (quote (1 2 3)) as ’(1 2 3).
So it looks like you are parsing it correctly.
@soegaard2 > The reader turns ’(1 2 3) into (quote (1 2 3)) In other words, I just need to create a list which has a symbol called quote at head? Then OK?
Yes.
@soegaard2 Thank you:smiley:
I am trying to understand dot. > (cons 1 2)
'(1 . 2) > (cons 0 (cons 1 2))
'(0 1 . 2) It seems that dot just is a infix operator for cons.
But what happen when dot appears multiple times in parentheses? E.g. > '(1 2 . 3 . 4)
'(3 1 2 4)
Thanks @sorawee. But I have to go to sleep:sleeping:. I will come back tomorrow (take a closer look at the documentation, because I just want to parse standard lisp syntax rather than extended syntax)