S39

138 views
Skip to first unread message

dr.mt...@gmail.com

unread,
Jun 22, 2024, 2:47:25 PM (11 days ago) Jun 22
to Shen
S39 will come out soon. It's already operative and supports
the Shen IDE under development.  The main changes are these.

1.  fn is defined for zero place functions

Previously fn around a zero place function resulted in an error.  
It was not clear what was the logical choice for the value of
(e.g) (fn pi) where (pi) in the standard library denotes the
value of p.   It could not be a lambda function.

The issue came up actually from ChatGPT which came up with 
this function

(define len
  {--> ((list A) --> number)}
  -> (/. X (if (empty? X)
               0
               (+ 1 (len (tail X))))))


This function does not run or typecheck under S38.2 because it generates
an fn in Kl if typed to the top level.  Under S39, it both runs and typechecks.
The new convention is that (fn f) denotes the object denoted by (f) if f is zero
place.

2.  Small change to trace.

Uses adjoin and not cons to avoid repeating functions listed as traced.

3.  A number of new utility functions for querying global variables in the kernel.

This was needed to produce a type secure IDE.

Mark

nha...@gmail.com

unread,
Jun 27, 2024, 5:22:24 PM (6 days ago) Jun 27
to Shen
suggestion: simple-error should be modified to accept either a string *or* exception object.

dr.mt...@gmail.com

unread,
Jun 28, 2024, 4:14:10 AM (5 days ago) Jun 28
to Shen
I don't think I'd endorse that for several reasons.

The first is that this involves mandating a change in the semantics of the
primitives that drive the kernel and I tend to avoid those changes.   This is not
a change that can be effected by me changing the kernel code.  I have
no power to force porters to revise their work.    The second
is that I can't see a compelling reason for wanting to do that given that
exceptions can be trapped anywhere and examined for their content.

People would be free to add this feature to a port but the price of doing so
would be that programs which used this feature would not be generally portable.

Mark

nha...@gmail.com

unread,
Jun 29, 2024, 2:17:21 PM (4 days ago) Jun 29
to Shen
"The second is that I can't see a compelling reason for wanting to do that given that exceptions can be trapped anywhere and examined for their content."

Because exceptions can't be propagated without discarding all information from the exception object except for its message string.

Consider common exception handlers which clean up file handles and rethrow the exception. You lose all debug information related to where the original exception was first generated.

It's true that debug facilities are platform specific, but the current Shen behaviour cripples all platforms for no good reason. 

dr.mt...@gmail.com

unread,
Jun 30, 2024, 1:14:00 AM (3 days ago) Jun 30
to Shen
Its not clear what you were asking for in saying simple-error
should be able to accept exceptions because an exception can
be thrown anywhere in a program.  Therefore any function can
receive an exception.  It is a bit clearer when you say that information
is lost when an exception is turned into a string.  But that
depends on the behaviour of error-to-string and there is nothing
in the Shen spec to say that information is lost.  Or is the argument
that there is some information in an exception that cannot be rendered
into text and is in some sense ineffable?

M. 

nha...@gmail.com

unread,
Jun 30, 2024, 3:10:16 PM (3 days ago) Jun 30
to Shen
"Its not clear what you were asking for in saying simple-error should be able to accept exceptions"
Exception objects. What X is bound to in (trap-error ... (/. X X)) 

"Or is the argument that there is some information in an exception that cannot be rendered into text and is in some sense ineffable?"
Yeah the exception object in Chez Scheme contains the continuation closure, and potentially other objects, which can't be recovered from a string representation.
Even if you could convert them to string, you would still have issues with error-to-string having a lousy API. If error-to-string encodes the fancy exception object in some platform specific way into a string, then exception messages can't be printed properly, because they would have to be parsed from a format that differs depending on the backend, and it raises the question of why even bother having an error-to-string function if it can't be used to pretty print just the exception message without serialised debug info. It would make it impossible to compare strings for certain specific exceptions as well, because the string encoded by error-to-string would be dependent on the execution history. Also every call to error-to-string would append unwanted data to the exception string at every propagation point which re-throws the same exception.

While it's true that you can't force people to update their ports, you do control whatever is considered the current specification of Shen. My proposed change is extremely simple and doesn't break pre-existing code because it just extends the valid input domain of the simple-error function. It was 1-2 lines of code changes in the Scheme port, simply adding a conditional branch:

  (define (throw-exception sys who msg)
    (raise (if (string? msg)
               (make-shen-exception-condition who msg sys)
               msg)))


To be more concrete, consider below this arbitrary exception that happens to be sitting in my REPL at the moment. The stack trace is extracted from the continuation data in the exception object. Every $guard frame is a Shen trap-error point btw.

  0: #<continuation in kl:_7#_rt_pl_eval_apply.prolog.apply>
  1: #<continuation in kl:_8#typecheck.toplevel-check>
  2: #<continuation in kl:_8#rewrite-system.dispatch>
  3: #<continuation>
  4: #<system continuation>
  5: #<system continuation in dynamic-wind>
  6: #<system continuation in $guard>
  7: #<continuation in kl:_8#rewrite-system.step>
  8: #<continuation>
  9: #<system continuation>
  10: #<system continuation in dynamic-wind>
  11: #<system continuation in $guard>
  12: #<continuation>
  13: #<system continuation>
  14: #<system continuation in dynamic-wind>
  15: #<system continuation in $guard>
  16: #<continuation in kl:_8#load.toplevel>
  17: #<continuation>
  18: #<continuation in kl:_8#repl.branch>
  19: #<continuation>
  20: #<continuation>
  21: #<system continuation>
  22: #<system continuation in dynamic-wind>
  23: #<system continuation in $guard>
  24: #<continuation>
  25: #<system continuation>
  26: #<system continuation in dynamic-wind>
  27: #<system continuation in $guard>
  28: #<continuation>
  29: #<system continuation>
  30: #<system continuation in dynamic-wind>
  31: #<system continuation in $guard>
  32: #<continuation>
  33: #<system continuation>
  34: #<system continuation in dynamic-wind>
  35: #<system continuation in $guard>
  36: #<continuation in kl:_8#repl.enter>
  37: #<system continuation in new-cafe>

dr.mt...@gmail.com

unread,
Jul 1, 2024, 5:27:48 AM (2 days ago) Jul 1
to Shen
So it a matter, then, of exceptions containing ineffable objects and the
example is drawn from Chez Scheme.  The thing is, that while one can
reasonably assume that an exception can be mapped to a string - and this
has proved portable - you can't really make assumptions about what ineffable
objects exist in an exception, their number and nature.  In such a case
the accepted solution is to place a port-specific solution 
(e.g. exception-to-chez-objects) that works for your port and adjust 
the type theory accordingly.

Mark

dr.mt...@gmail.com

unread,
Jul 1, 2024, 1:21:03 PM (2 days ago) Jul 1
to Shen
Looking at your examples, I think your complaint is that just raising a string
at the point of error loses too much valuable information.  This can be true,
but you can roll your own. For example to take Shen Prolog as an example; 
here is an error handler that passes information.
.    
(0-) (define prolog-error
      X Bindings Lock Key Continuation -> (do (set *prolog-error* [X Bindings Lock Key Continuation])
                                              (simple-error "Prolog error")))
(fn my-prolog-error)

(1-) (define view-prolog-error
   -> (value *prolog-error*))
(fn view-prolog-error)

(2-) (defprolog member
  X [X | _] <--;
  X [_ | Y] <-- (member X Y);
  X Y       <-- (prolog-error [member X Y]);)
(fn member)

(3-) (prolog? (member 1 2))
Prolog error

(4-) (view-prolog-error)
[[member 1 2] |prolog vector| <true 0> 0 #<FUNCTION (LAMBDA ()) {2611007D}>]


view-prolog-error now allows us to recover all relevant information at the point when the
error was raised.  I've shown this for Prolog, but the structures that need to be examined
are application specific and in other programs could include the status of global and local
variables defined by the programmer. So IMO this is something best left to the applications
programmer.

Mark

Reply all
Reply to author
Forward
0 new messages