example-00.scm 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. ;; =========
  2. ;; UTILITIES
  3. ;; =========
  4. (define even-simpler-display
  5. (lambda (sth)
  6. (display
  7. (simple-format
  8. #f "~a\n" sth))))
  9. ;; ==========================
  10. ;; NON-CONTINUABLE EXCEPTIONS
  11. ;; ==========================
  12. (define erroroneous-proc-division
  13. (lambda (dividend divisor)
  14. ;; Division by zero will raise an uncontinuable exception. "uncontinuable"
  15. ;; means, that at here, at this very point, the execution cannot continue,
  16. ;; meaning, that erroroneous-proc-division does not know, what to do next,
  17. ;; when it receives a divisor equal to zero.
  18. (/ dividend divisor)))
  19. ;; Use an exception handler to handle the exception thrown when dividing by
  20. ;; zero. `with-exception-handler` takes 2 arguments. The installed exception
  21. ;; handler and the code to run wrapped in a lambda to avoid immediate
  22. ;; evaluation, called a "thunk".
  23. (with-exception-handler
  24. ;; The exception handler takes 1 argument, which is whatever is given to
  25. ;; `raise` or `raise-continuable` when the exception is raised. In the case
  26. ;; of dividing by zero, we get a `#<r6rs:record:&compound-condition>`, which
  27. ;; we can inspect.
  28. (lambda (condition-or-value)
  29. (display
  30. (simple-format
  31. #f
  32. (string-append "====\n"
  33. "condition or value:\n"
  34. "~a\n"
  35. "====\n")
  36. condition-or-value)))
  37. ;; The thunk is always a procedure taking 0 arguments. Its invocation is
  38. ;; running the code, which could cause an exception.
  39. (lambda ()
  40. ;; Divide by zero to cause an exception. Dividing by zero will result in a
  41. ;; non-continuable exception. The exception will be dealt with and the
  42. ;; program will then exit with an error.(simple-conditions condition)
  43. (erroroneous-proc-division 1 0))
  44. ;; From the Guile reference manual:
  45. ;; "[...] it’s often the case that one would like to handle an exception by
  46. ;; unwinding the computation to an earlier state and running the error handler
  47. ;; there. After all, unless the raise-exception call is continuable, the
  48. ;; exception handler needs to abort the continuation. To support this use
  49. ;; case, if with-exception-handler was invoked with #:unwind? #t is true,
  50. ;; raise-exception will first unwind the stack by invoking an escape
  51. ;; continuation (see call/ec), and then invoke the handler with the
  52. ;; continuation of the with-exception-handler call." --
  53. ;; https://www.gnu.org/software/guile/docs/master/guile.html/Raising-and-Handling-Exceptions.html
  54. ;; Here the exception is non-continuable, so according to the reference
  55. ;; manual, we need to call with-exception-handler with #:unwind? being set to
  56. ;; #t for normal exception handling. If we do not do this, a (different?)
  57. ;; non-continuable exception is raised.
  58. ;; Q: Why unwind the stack?
  59. ;; A:
  60. ;; If the execution cannot be continued (non-continuable exception) at the
  61. ;; point, where the exception is raised, it means, that in that context, there
  62. ;; was insufficient information to continue the execution in useful way.
  63. ;; Unwinding the stack means discarding stack frames of procedure calls. This
  64. ;; happens up to the point, where an exception handler is defined. The result
  65. ;; of unwinding the stack is, that we only leave intact the environment, which
  66. ;; was available when the exception handler was defined.
  67. ;; We have the knowledge at this point, that an exception occurred. That is
  68. ;; more than we knew, when we called the procedure, which raised the
  69. ;; exception. Furthermore the exception can contain information about the kind
  70. ;; of thing that went wrong. This information hand-over facility should be
  71. ;; used to give sufficient information to the exception handler, so that the
  72. ;; handler can continue execution in a useful way. The exception enables us to
  73. ;; store important information from the environment at the point where the
  74. ;; exception was raised. Then we have no need to keep the environment of the
  75. ;; point, where the exception was raised and can unwind the stack.
  76. #:unwind? #t)
  77. ;; Lets see what happens, if we do not set #:unwind? to #t. (Note: This example
  78. ;; should result in an exception, even though we are using
  79. ;; with-exception-handler, because we are doing it the wrong way.)
  80. (with-exception-handler
  81. (lambda (condition-or-value)
  82. (display
  83. (simple-format
  84. #f
  85. (string-append "====\n"
  86. "condition or value:\n"
  87. "~a\n"
  88. "====\n")
  89. condition-or-value)))
  90. (lambda ()
  91. (erroroneous-proc-division 1 0))
  92. ;; #:unwind? #f is the default.
  93. #:unwind? #f)
  94. ;; As described above, a non-continuable exception is raised and the program
  95. ;; breaks, which is usually not what one wants in many cases.
  96. ;; ======================
  97. ;; CONTINUABLE EXCEPTIONS
  98. ;; ======================
  99. ;; Here is another procedure, which raises a continuable exception. When it is
  100. ;; dealt with, the program will continue and not exit with the error.
  101. (define erroroneous-proc-2
  102. (lambda ()
  103. (raise-continuable "I am an error.")))
  104. (with-exception-handler
  105. (lambda (condition-or-value)
  106. (display (simple-format #f "~a\n" condition-or-value)))
  107. (lambda ()
  108. (erroroneous-proc-2)))