example-01-rnrs-exceptions-conditions.scm 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. (use-modules
  2. (rnrs exceptions)
  3. (rnrs conditions))
  4. ;; =========
  5. ;; UTILITIES
  6. ;; =========
  7. (define even-simpler-display
  8. (lambda (sth)
  9. (display
  10. (simple-format
  11. #f "~a\n" sth))))
  12. ;; =====
  13. ;; INTRO
  14. ;; =====
  15. ;; Conditions are a concept from R6RS exception handling. A condition is created
  16. ;; using the constructor ~condition~ from R6RS or
  17. ;; Conditions can be "simple" or "compound". A simple condition describes a
  18. ;; single aspect of an exceptional situation. A compound condition contains a
  19. ;; list of simple conditions, which together describe multiple aspects of an
  20. ;; exceptional situation. The list of simple conditions of a compound condition
  21. ;; is called components of the compound condition.
  22. ;; Next let us see how we can work with conditions, when we get them.
  23. ;; ==========
  24. ;; CONDITIONS
  25. ;; ==========
  26. ;; The standard already defines a few constructors for so called standard
  27. ;; condition types:
  28. ;; - (make-message-condition message)
  29. ;; - (make-warning)
  30. ;; - (make-serious-condition) ; intended as supertype
  31. ;; - (make-violation)
  32. ;; - (make-assertion-violation)
  33. ;; - (make-irritants-condition irritants)
  34. ;; - (make-who-condition who)
  35. ;; - (make-non-continuable-violation)
  36. ;; - (make-implementation-restriction-violation)
  37. ;; - (make-lexical-violation)
  38. ;; - (make-syntax-violation form subform)
  39. ;; - (make-undefined-violation)
  40. ;; These have a predefined purpose, but probably already cover a lot of
  41. ;; ground. Lets try to make use of them:
  42. (define divide
  43. (lambda (a b)
  44. (cond
  45. [(= b 0)
  46. (raise ; raise from rnrs exceptions
  47. (condition
  48. (make-error)
  49. (make-message-condition "division by zero")
  50. (make-irritants-condition (list a b))
  51. (make-who-condition 'divide)))]
  52. [else
  53. (/ a b)])))
  54. (with-exception-handler
  55. (lambda (conditions-or-value)
  56. (even-simpler-display
  57. ;; We can get the simple conditions from a compound condition with the
  58. ;; `simple-conditions` getter.
  59. (simple-conditions conditions-or-value)))
  60. (lambda ()
  61. (divide 2 0))
  62. ;; We need to unwind the stack here. For explanation see the other examples.
  63. #:unwind? #t)
  64. ;; ======
  65. ;; GUARDS
  66. ;; ======
  67. ;; R6RS's or R7RS's guard expression is a wrapper around with-exception-handler
  68. ;; with #:unwind? set to #t. It is a macro enabling some convenience. The guard
  69. ;; expression allows for a cond expression, which enables to specify different
  70. ;; handlers for different exception.
  71. (guard
  72. ;; First a binding is defined, which will be bound to the raised
  73. ;; object. This can be a condition or a raised value.
  74. (con
  75. ;; First we check, whether the condition is an error. This could be a
  76. ;; compound condition, which contains a simple condition produced by
  77. ;; `make-error`, or it could be only a simple condition produced by
  78. ;; `make-error`.
  79. [(error? con)
  80. (if (message-condition? con)
  81. (even-simpler-display (condition-message con))
  82. (even-simpler-display "an error has occurred"))
  83. ;; We also return the symbol 'error, to signal, that some kind of error
  84. ;; occurred to whatever expects a return value from the guard form.
  85. 'error]
  86. ;; We can in other cases of the guard check for different errors.
  87. [(violation? con)
  88. (if (message-condition? con)
  89. (even-simpler-display (condition-message con))
  90. (even-simpler-display "the program has a bug"))
  91. 'violation])
  92. ;; Write something here, which could cause an exceptional situation.
  93. (raise
  94. (condition
  95. (make-error)
  96. (make-message-condition "I am an error"))))
  97. ;; If no branch of the guard catches the condition, it will be raised again.
  98. (guard
  99. (con
  100. ((error? con)
  101. (if (message-condition? con)
  102. (display (condition-message con))
  103. (display "an error has occurred"))
  104. 'error))
  105. (raise
  106. (condition
  107. (make-violation
  108. (make-message-condition "I am an error")))))
  109. ;; Another example:
  110. (guard
  111. (con
  112. [(error? con)
  113. (if (message-condition? con)
  114. (even-simpler-display (condition-message con))
  115. (even-simpler-display "an error has occurred"))
  116. 'error]
  117. [else])
  118. (divide 314 0))
  119. ;; Advantages of using `guard`: We can see, that the guard makes it unnecessary
  120. ;; to wrap the code we want to run in a lambda to delay evaluation. This is
  121. ;; taken care of by the guard form itself. Also the guard form already provides
  122. ;; the cond like structure, so there is no need to write a cond.