From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Juliana Sims via "Bug reports for GUILE, GNU's Ubiquitous Extension Language" Newsgroups: gmane.lisp.guile.bugs Subject: bug#71684: [PATCH] doc: Document the peek and pk procedures. Date: Thu, 20 Jun 2024 14:54:15 -0400 Message-ID: <20240620185415.9088-1-juli@incana.org> Reply-To: Juliana Sims Mime-Version: 1.0 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="1930"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Juliana Sims To: 71684@debbugs.gnu.org Original-X-From: bug-guile-bounces+guile-bugs=m.gmane-mx.org@gnu.org Thu Jun 20 20:56:24 2024 Return-path: Envelope-to: guile-bugs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1sKMxL-0000GK-9r for guile-bugs@m.gmane-mx.org; Thu, 20 Jun 2024 20:56:23 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sKMwz-0000mf-At; Thu, 20 Jun 2024 14:56:01 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sKMwx-0000kq-DM for bug-guile@gnu.org; Thu, 20 Jun 2024 14:55:59 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sKMww-0007Wc-Un for bug-guile@gnu.org; Thu, 20 Jun 2024 14:55:59 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1sKMwz-0006EQ-TZ for bug-guile@gnu.org; Thu, 20 Jun 2024 14:56:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Juliana Sims Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Thu, 20 Jun 2024 18:56:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 71684 X-GNU-PR-Package: guile X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-guile@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.171890970323850 (code B ref -1); Thu, 20 Jun 2024 18:56:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 20 Jun 2024 18:55:03 +0000 Original-Received: from localhost ([127.0.0.1]:40361 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sKMw2-0006Cb-Lt for submit@debbugs.gnu.org; Thu, 20 Jun 2024 14:55:03 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:37306) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sKMvz-0006C6-Tq for submit@debbugs.gnu.org; Thu, 20 Jun 2024 14:55:01 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sKMvv-0000M1-Ia for bug-guile@gnu.org; Thu, 20 Jun 2024 14:54:55 -0400 Original-Received: from out-176.mta0.migadu.com ([2001:41d0:1004:224b::b0]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sKMvs-00079i-R0 for bug-guile@gnu.org; Thu, 20 Jun 2024 14:54:55 -0400 X-Envelope-To: bug-guile@gnu.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=incana.org; s=key1; t=1718909688; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=KpiGpSZmiyctv0wiOwbcy7ef2/mV+XkDhirN8stkQro=; b=jEtS4GTk324yW+TgQ3V4BA0rEWXF6XJTs9AyHobxgspL3MDoiD0EPjyijBqqOb76++v2yG KukXKqnvezhqKBsWT+k260CBJZQgNjXisLmYkCbz+F2e1rLqZGq2dpOj8y9IIHUXkSKLBE rUy7jejR6J2aIROtqimoAzhftsXqusW6LMn7jxQMwqHAJ/vnKjU8JKHhnxPSywrZgkaZb2 OqT4JnQPtqp7wqxm1/E5h6x2eWkMxJl/OKGNHTv0CH+e+7cAepnUWQkWfaUEKDyieVtXJG x4OOJAFz5nzZkdCrsJfawQsN4i4dK2eRgEbWUuMHSUYNNve2G5ZkHKwe9OdD4g== X-Envelope-To: juli@incana.org X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:1004:224b::b0; envelope-from=juli@incana.org; helo=out-176.mta0.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-guile@gnu.org List-Id: "Bug reports for GUILE, GNU's Ubiquitous Extension Language" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-guile-bounces+guile-bugs=m.gmane-mx.org@gnu.org Original-Sender: bug-guile-bounces+guile-bugs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.lisp.guile.bugs:10865 Archived-At: * doc/ref/api-debug.texi: Document the peek and pk procedures. --- doc/ref/api-debug.texi | 187 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 8 deletions(-) diff --git a/doc/ref/api-debug.texi b/doc/ref/api-debug.texi index faa0c40bd..486473cdb 100644 --- a/doc/ref/api-debug.texi +++ b/doc/ref/api-debug.texi @@ -1,27 +1,198 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2007, 2010, 2011, 2012, 2013, 2014, 2018, 2021 +@c Copyright (C) 1996-1997, 2000-2004, 2007, 2010-2014, 2018, 2021, 2024 @c Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @node Debugging @section Debugging Infrastructure -@cindex Debugging -In order to understand Guile's debugging facilities, you first need to -understand a little about how Guile represents the Scheme control stack. -With that in place we explain the low level trap calls that the virtual -machine can be configured to make, and the trap and breakpoint -infrastructure that builds on top of those calls. +@cindex debugging +Guile provides facilities for simple print-based debugging as well as +more advanced debugging features. In order to understand Guile's +advanced debugging facilities, one first must understand a little about +how Guile represents the Scheme control stack. With that in place, we +can explain the low level trap calls that the virtual machine can be +configured to make, and the trap and breakpoint infrastructure that +builds on top of those calls. @menu +* Simple Debugging:: Print-based debugging. * Evaluation Model:: Evaluation and the Scheme stack. * Source Properties:: From expressions to source locations. -* Programmatic Error Handling:: Debugging when an error occurs. +* Programmatic Error Handling:: Debugging when an error occurs. * Traps:: Breakpoints, tracepoints, oh my! * GDB Support:: C-level debugging with GDB. @end menu + +@node Simple Debugging +@subsection Simple Debugging + +Guile offers powerful tools for introspection and debugging at the REPL, +covered in the rest of this section and elsewhere in this manual +(@pxref{Interactive Debugging}). Here we deal with a more primitive +approach, commonly called ``print debugging.'' Let's be honest: for most +of us, this is our first line of debugging. And Guile doesn't judge us +for it! Instead, Guile provides a powerful and convenient tool to +facilitate print debugging: the @code{peek} procedure, more commonly +known as @code{pk} (pronounced by naming the letters). + +@deffn {Scheme Procedure} peek stuff @dots{} +@deffnx {Scheme Procedure} pk stuff @dots{} +Print @var{stuff} to the current output port using @code{write}. Return +the last argument. +@end deffn + +@code{pk} allows us to look at the state of our code as it runs without +having to step through it or break the normal code flow. Let's take a +look at how one might use it. Let's say we have a procedure to make a +smore, perhaps as part of a mod for a cozy space exploration game. + +@lisp +(define (make-smore marshmallow graham-crackers chocolate fire) + "Toast @var{mashmallow} over @var{fire} then sandwich it and +@var{chocolate} between @var{graham-crackers}." + (let ((toasted-marshmallow + (toast marshmallow fire))) + (unless (or (burned? toasted-marshmallow) + (undercooked? toasted-marshmallow)) + (cons (car graham-crackers) + (cons toasted-marshmallow + (cons chocolate + (cons (cdr graham-crackers) '()))))))) +@end lisp + +We've run this procedure a few times, and it isn't doing what we expect. +Instead of getting a tasty smore, we get nothing. Let's use @code{pk} to +find out what's going on. + +@lisp +(pk (make-smore (grab-one marshmallow-bag) + (cons graham-cracker graham-cracker) + campfire)) + +;;; (#) +@end lisp + +@code{#} is a value in Guile which indicates that no Scheme +standard specifies a return value for whatever is returning it. In this +case, it probably means that our @code{unless} check is not proving +true, so the procedure returns nothing. Let's add a @code{pk} around the +call to @code{toast} and see what happens. + +@lisp +(define (make-smore marshmallow graham-crackers chocolate fire) + "Toast @var{mashmallow} over @var{fire} then sandwich it and +@var{chocolate} between @var{graham-crackers}." + (let ((toasted-marshmallow + ;; Let's see what state the toasted-marshmallow is in + (pk 'toasted-marshmallow (toast marshmallow fire)))) + (unless (or (burned? toasted-marshmallow) + (undercooked? toasted-marshmallow)) + (cons (car graham-crackers) + (cons toasted-marshmallow + (cons chocolate + (cons (cdr graham-crackers) '()))))))) + +(make-smore (grab-one marshmallow-bag) + (cons graham-cracker graham-cracker) + campfire) + +;;; (toasted-marshmallow #< state: raw>) +@end lisp + +Our marshmallow isn't getting cooked at all! Let's see if we can find +out why. We'll check on the state of @var{fire} since we know that +@code{toast} just operates on the state of the fire and of the +marshmallow. @code{toasted-marshmallow} matches the state we expect for +a fresh marshmallow, so the problem is probably with the fire. + +@lisp +(define (make-smore marshmallow graham-crackers chocolate fire) + "Toast @var{mashmallow} over @var{fire} then sandwich it and +@var{chocolate} between @var{graham-crackers}." + (let ((toasted-marshmallow + ;; Now we'll check on the fire, too + (pk 'toasted-marshmallow (toast marshmallow (pk 'fire fire))))) + (unless (or (burned? toasted-marshmallow) + (undercooked? toasted-marshmallow)) + (cons (car graham-crackers) + (cons toasted-marshmallow + (cons chocolate + (cons (cdr graham-crackers) '()))))))) + +(make-smore (grab-one marshmallow-bag) + (cons graham-cracker graham-cracker) + campfire) + +;;; (fire #< state: unlit>) + +;;; (toasted-marshmallow #< state: raw>) +@end lisp + +Oh, well that makes sense! A fire can't cook a marshmallow if it isn't +lit! + +Notice that the result of evaluating the @code{pk} around @code{fire} is +printed before the one around @code{toast}. This is just the result of +the normal process of evaluating s-expressions from the inside out. We +highlight it because it can be confusing at first, especially with more +@code{pk}s in more complex code. + +Let's add a guard to light the fire and run our procedure again. + +@lisp +(define (make-smore marshmallow graham-crackers chocolate fire) + "Toast @var{mashmallow} over @var{fire} then sandwich it and +@var{chocolate} between @var{graham-crackers}." + (let ((toasted-marshmallow + (toast marshmallow fire))) + (unless (lit? fire) + (light fire)) + (unless (or (burned? toasted-marshmallow) + (undercooked? toasted-marshmallow)) + (cons (car graham-crackers) + (cons toasted-marshmallow + (cons chocolate + (cons (cdr graham-crackers) '()))))))) + +(make-smore (grab-one marshmallow-bag) + (cons graham-cracker graham-cracker) + campfire) +@result{} (#<> #< state: cooked> #<> #<>) +@end lisp + +Yay! Now it works, and we have a tasty smore! + +As we demonstrated, you can pass in any number of arguments and the +result of evaluating the last argument is the value returned from +@code{pk}. This is handy to, as we showed, wrap code in-line without +needing to add extra steps along the way while still providing +informative labels about what, exactly, is getting printed. We could as +easily have put @code{pk}s completely on their own, rather than wrapping +other code. This is commonly used to, for example, test if a given +procedure or part of a procedure is entered. Earlier, we could have put +a @code{pk} in the body of the @code{unless} clause to let us know if we +entered it, such as: + +@lisp +(define (make-smore ...) + ... + (unless ... + (pk 'inside-unless) + ...)) +@end lisp + +As a final note, labels don't have to be symbols. @code{pk} will happily +print any object we pass it. We could have used strings or anything else +we wanted alongside the code we were interested in. + +Hopefully this silly little example has shown the utility of @code{pk}. +Now that it's in your toolbox, go forth, newly empowered, and happy +hacking! + + @node Evaluation Model @subsection Evaluation and the Scheme Stack -- 2.45.1