* Proposal for a new (ice-9 history) @ 2018-10-29 14:13 Mikael Djurfeldt 2018-10-29 23:54 ` Mark H Weaver 2018-10-30 0:25 ` Proposal for a new (ice-9 history) Mark H Weaver 0 siblings, 2 replies; 13+ messages in thread From: Mikael Djurfeldt @ 2018-10-29 14:13 UTC (permalink / raw) To: guile-devel [-- Attachment #1: Type: text/plain, Size: 961 bytes --] I'd like to rewrite (ice-9 history) to conform to the full GDB value history syntax. This is because I find that I miss being able to refer to "the last value" etc. Currently we have: $<N> the N:th value from the start The extension would add bindings for: $$<N> the N:th value from the end $ the last value (= $$0) $$ the value just prior to the last value (= $$1) Implementation: Currently, every step in the REPL defines a $<N> in the module (value-history) the interface of which is appended to the list of used interfaces for the (current-module). The new implementation would just add a new result value to a list, not doing any definition. The interface of (value-history) would instead have a lazy-binder which provides a syntax transformer for every $... actually being used. The $... identifier would expand into a list-ref into the value history. Please evaluate this suggestion and give comments or an OK. Best regards, Mikael Djurfeldt [-- Attachment #2: Type: text/html, Size: 1343 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Proposal for a new (ice-9 history) 2018-10-29 14:13 Proposal for a new (ice-9 history) Mikael Djurfeldt @ 2018-10-29 23:54 ` Mark H Weaver 2018-10-30 0:55 ` Mikael Djurfeldt 2018-10-30 0:25 ` Proposal for a new (ice-9 history) Mark H Weaver 1 sibling, 1 reply; 13+ messages in thread From: Mark H Weaver @ 2018-10-29 23:54 UTC (permalink / raw) To: Mikael Djurfeldt; +Cc: guile-devel Hi Mikael, Mikael Djurfeldt <mikael@djurfeldt.com> writes: > I'd like to rewrite (ice-9 history) to conform to the full GDB value > history syntax. This is because I find that I miss being able to refer > to "the last value" etc. Yes, I've also missed this! > Currently we have: > > $<N> the N:th value from the start > > The extension would add bindings for: > > $$<N> the N:th value from the end > > $ the last value (= $$0) > > $$ the value just prior to the last value (= $$1) > > Implementation: > > Currently, every step in the REPL defines a $<N> in the module > (value-history) the interface of which is appended to the list of used > interfaces for the (current-module). > > The new implementation would just add a new result value to a list, > not doing any definition. > > The interface of (value-history) would instead have a lazy-binder > which provides a syntax transformer for every $... actually being > used. The $... identifier would expand into a list-ref into the value > history. > > Please evaluate this suggestion and give comments or an OK. This strategy sounds good to me. I'd also like to hear what Andy and Ludovic think. However, there's a complication with using '$' in this way. '$' is already widely used as part of the syntax for (ice-9 match), to specify patterns that match record objects. More precisely, it is a literal identifier recognized by 'match' and related macros, in the same sense that 'else' and '=>' are literal identifiers recognized by the 'cond' macro. R5RS section 4.3.2 (Pattern language) specifies how these literal identifiers are to be compared with identifiers found in each macro use: Identifiers that appear in <literals> are interpreted as literal identifiers to be matched against corresponding subforms of the input. A subform in the input matches a literal identifier if and only if it is an identifier and either both its occurrence in the macro expression and its occurrence in the macro definition have the same lexical binding, or the two identifiers are equal and both have no lexical binding. The implication is that these literal identifiers such as 'else', '=>' and '$' lose their special meaning in any environment where they are bound, unless the same binding is visible in the corresponding macro definition environment. R6RS and R7RS also specify this behavior. For example: --8<---------------cut here---------------start------------->8--- mhw@jojen ~$ guile GNU Guile 2.2.3 Copyright (C) 1995-2017 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)> ,use (ice-9 match) scheme@(guile-user)> ,use (srfi srfi-9) scheme@(guile-user)> (define-record-type <foo> (make-foo a b) foo? (a foo-a) (b foo-b)) scheme@(guile-user)> (match (make-foo 1 2) (($ <foo> a b) (+ a b))) $1 = 3 scheme@(guile-user)> (define $ 'blah) scheme@(guile-user)> (match (make-foo 1 2) (($ <foo> a b) (+ a b))) <unnamed port>:6:0: Throw to key `match-error' with args `("match" "no matching pattern" #<<foo> a: 1 b: 2>)'. Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. scheme@(guile-user) [1]> --8<---------------cut here---------------end--------------->8--- To avoid colliding with the popular 'match' syntax, how about making '$$' the last value ($$0), and omitting the alias for '$$1'? What do you think? Regards, Mark ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Proposal for a new (ice-9 history) 2018-10-29 23:54 ` Mark H Weaver @ 2018-10-30 0:55 ` Mikael Djurfeldt 2018-10-30 10:21 ` REPL and load deifferences (was Re: Proposal for a new (ice-9 history)) Mikael Djurfeldt 0 siblings, 1 reply; 13+ messages in thread From: Mikael Djurfeldt @ 2018-10-30 0:55 UTC (permalink / raw) To: Mark H Weaver; +Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 2949 bytes --] On Tue, Oct 30, 2018 at 12:55 AM Mark H Weaver <mhw@netris.org> wrote: > However, there's a complication with using '$' in this way. '$' is > already widely used as part of the syntax for (ice-9 match), to specify > patterns that match record objects. Yes, I actually looked at this, but thought that $ would be interpreted as a literal inside the match expression, but was probably wrong according to what you write below: > More precisely, it is a literal > identifier recognized by 'match' and related macros, in the same sense > that 'else' and '=>' are literal identifiers recognized by the 'cond' > macro. > > R5RS section 4.3.2 (Pattern language) specifies how these literal > identifiers are to be compared with identifiers found in each macro use: > > Identifiers that appear in <literals> are interpreted as literal > identifiers to be matched against corresponding subforms of the > input. A subform in the input matches a literal identifier if and > only if it is an identifier and either both its occurrence in the > macro expression and its occurrence in the macro definition have > the same lexical binding, or the two identifiers are equal and both > have no lexical binding. > > The implication is that these literal identifiers such as 'else', '=>' > and '$' lose their special meaning in any environment where they are > bound, unless the same binding is visible in the corresponding macro > definition environment. R6RS and R7RS also specify this behavior. > > For example: > > --8<---------------cut here---------------start------------->8--- > mhw@jojen ~$ guile > GNU Guile 2.2.3 > Copyright (C) 1995-2017 Free Software Foundation, Inc. > > Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. > This program is free software, and you are welcome to redistribute it > under certain conditions; type `,show c' for details. > > Enter `,help' for help. > scheme@(guile-user)> ,use (ice-9 match) > scheme@(guile-user)> ,use (srfi srfi-9) > scheme@(guile-user)> (define-record-type <foo> (make-foo a b) foo? (a > foo-a) (b foo-b)) > scheme@(guile-user)> (match (make-foo 1 2) (($ <foo> a b) (+ a b))) > $1 = 3 > scheme@(guile-user)> (define $ 'blah) > scheme@(guile-user)> (match (make-foo 1 2) (($ <foo> a b) (+ a b))) > <unnamed port>:6:0: Throw to key `match-error' with args `("match" "no > matching pattern" #<<foo> a: 1 b: 2>)'. > > Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. > scheme@(guile-user) [1]> > --8<---------------cut here---------------end--------------->8--- > Incidentally, this does *not* throw an error in master (unless I made some mistake in this late hour), which then is a bug! > > To avoid colliding with the popular 'match' syntax, how about making > '$$' the last value ($$0), and omitting the alias for '$$1'? > > What do you think? > Not sure. This might be confusing for GDB users... Let's think about it. [-- Attachment #2: Type: text/html, Size: 3913 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* REPL and load deifferences (was Re: Proposal for a new (ice-9 history)) 2018-10-30 0:55 ` Mikael Djurfeldt @ 2018-10-30 10:21 ` Mikael Djurfeldt 2018-10-30 12:20 ` Mikael Djurfeldt 0 siblings, 1 reply; 13+ messages in thread From: Mikael Djurfeldt @ 2018-10-30 10:21 UTC (permalink / raw) To: Mark H Weaver; +Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 3610 bytes --] On Tue, Oct 30, 2018 at 1:55 AM Mikael Djurfeldt <mikael@djurfeldt.com> wrote: > On Tue, Oct 30, 2018 at 12:55 AM Mark H Weaver <mhw@netris.org> wrote: > >> More precisely, it is a literal >> identifier recognized by 'match' and related macros, in the same sense >> that 'else' and '=>' are literal identifiers recognized by the 'cond' >> macro. >> >> R5RS section 4.3.2 (Pattern language) specifies how these literal >> identifiers are to be compared with identifiers found in each macro use: >> >> Identifiers that appear in <literals> are interpreted as literal >> identifiers to be matched against corresponding subforms of the >> input. A subform in the input matches a literal identifier if and >> only if it is an identifier and either both its occurrence in the >> macro expression and its occurrence in the macro definition have >> the same lexical binding, or the two identifiers are equal and both >> have no lexical binding. >> >> The implication is that these literal identifiers such as 'else', '=>' >> and '$' lose their special meaning in any environment where they are >> bound, unless the same binding is visible in the corresponding macro >> definition environment. R6RS and R7RS also specify this behavior. >> >> For example: >> >> --8<---------------cut here---------------start------------->8--- >> mhw@jojen ~$ guile >> GNU Guile 2.2.3 >> Copyright (C) 1995-2017 Free Software Foundation, Inc. >> >> Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. >> This program is free software, and you are welcome to redistribute it >> under certain conditions; type `,show c' for details. >> >> Enter `,help' for help. >> scheme@(guile-user)> ,use (ice-9 match) >> scheme@(guile-user)> ,use (srfi srfi-9) >> scheme@(guile-user)> (define-record-type <foo> (make-foo a b) foo? (a >> foo-a) (b foo-b)) >> scheme@(guile-user)> (match (make-foo 1 2) (($ <foo> a b) (+ a b))) >> $1 = 3 >> scheme@(guile-user)> (define $ 'blah) >> scheme@(guile-user)> (match (make-foo 1 2) (($ <foo> a b) (+ a b))) >> <unnamed port>:6:0: Throw to key `match-error' with args `("match" "no >> matching pattern" #<<foo> a: 1 b: 2>)'. >> >> Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. >> scheme@(guile-user) [1]> >> --8<---------------cut here---------------end--------------->8--- >> > > Incidentally, this does *not* throw an error in master (unless I made some > mistake in this late hour), which then is a bug! > I now looked at this a bit more. It turns out that the difference is not between stable-2.2 and master, but between REPL and load. While I can reproduce the above also in master, if I instead load it (attached file matchcoll.scm), I get no error! Also, the following file (attached as "elsetest.scm"): ------------------------------ (display (cond (else #t))) (newline) (define else #f) (display (cond (else #t))) (newline) ------------------------------ gives the results #t and #<unspecified>, as expected, in the REPL, but if I load the file, I instead get: scheme@(guile-user)> (load "elsetest.scm") /home/mdj/guile/elsetest.scm:7:0: Unbound variable: else If I load it into Chez Scheme, I get: #t #<void> as expected. Maybe someone more knowledgeable than myself could sort out what out of this is a bug? Also, I have to rant a bit about R5RS section 4.3.2. What a mess this is! To have the literals influenced by bindings outside goes against the spirit of lexical binding, in my opinion, where the idea is to be able to judge the outcome of the code from looking at it locally. Best regards, Mikael [-- Attachment #2: Type: text/html, Size: 4831 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: REPL and load deifferences (was Re: Proposal for a new (ice-9 history)) 2018-10-30 10:21 ` REPL and load deifferences (was Re: Proposal for a new (ice-9 history)) Mikael Djurfeldt @ 2018-10-30 12:20 ` Mikael Djurfeldt 2018-10-30 18:01 ` Göran Weinholt 0 siblings, 1 reply; 13+ messages in thread From: Mikael Djurfeldt @ 2018-10-30 12:20 UTC (permalink / raw) To: Mark H Weaver; +Cc: guile-devel [-- Attachment #1.1: Type: text/plain, Size: 3847 bytes --] And, the attachments... On Tue, Oct 30, 2018 at 11:21 AM Mikael Djurfeldt <mikael@djurfeldt.com> wrote: > On Tue, Oct 30, 2018 at 1:55 AM Mikael Djurfeldt <mikael@djurfeldt.com> > wrote: > >> On Tue, Oct 30, 2018 at 12:55 AM Mark H Weaver <mhw@netris.org> wrote: >> >>> More precisely, it is a literal >>> identifier recognized by 'match' and related macros, in the same sense >>> that 'else' and '=>' are literal identifiers recognized by the 'cond' >>> macro. >>> >>> R5RS section 4.3.2 (Pattern language) specifies how these literal >>> identifiers are to be compared with identifiers found in each macro use: >>> >>> Identifiers that appear in <literals> are interpreted as literal >>> identifiers to be matched against corresponding subforms of the >>> input. A subform in the input matches a literal identifier if and >>> only if it is an identifier and either both its occurrence in the >>> macro expression and its occurrence in the macro definition have >>> the same lexical binding, or the two identifiers are equal and both >>> have no lexical binding. >>> >>> The implication is that these literal identifiers such as 'else', '=>' >>> and '$' lose their special meaning in any environment where they are >>> bound, unless the same binding is visible in the corresponding macro >>> definition environment. R6RS and R7RS also specify this behavior. >>> >>> For example: >>> >>> --8<---------------cut here---------------start------------->8--- >>> mhw@jojen ~$ guile >>> GNU Guile 2.2.3 >>> Copyright (C) 1995-2017 Free Software Foundation, Inc. >>> >>> Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. >>> This program is free software, and you are welcome to redistribute it >>> under certain conditions; type `,show c' for details. >>> >>> Enter `,help' for help. >>> scheme@(guile-user)> ,use (ice-9 match) >>> scheme@(guile-user)> ,use (srfi srfi-9) >>> scheme@(guile-user)> (define-record-type <foo> (make-foo a b) foo? (a >>> foo-a) (b foo-b)) >>> scheme@(guile-user)> (match (make-foo 1 2) (($ <foo> a b) (+ a b))) >>> $1 = 3 >>> scheme@(guile-user)> (define $ 'blah) >>> scheme@(guile-user)> (match (make-foo 1 2) (($ <foo> a b) (+ a b))) >>> <unnamed port>:6:0: Throw to key `match-error' with args `("match" "no >>> matching pattern" #<<foo> a: 1 b: 2>)'. >>> >>> Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. >>> scheme@(guile-user) [1]> >>> --8<---------------cut here---------------end--------------->8--- >>> >> >> Incidentally, this does *not* throw an error in master (unless I made >> some mistake in this late hour), which then is a bug! >> > > I now looked at this a bit more. It turns out that the difference is not > between stable-2.2 and master, but between REPL and load. While I can > reproduce the above also in master, if I instead load it (attached file > matchcoll.scm), I get no error! > > Also, the following file (attached as "elsetest.scm"): > ------------------------------ > (display (cond (else #t))) > (newline) > > (define else #f) > > (display (cond (else #t))) > (newline) > ------------------------------ > > gives the results #t and #<unspecified>, as expected, in the REPL, but if > I load the file, I instead get: > > scheme@(guile-user)> (load "elsetest.scm") > /home/mdj/guile/elsetest.scm:7:0: Unbound variable: else > > If I load it into Chez Scheme, I get: > > #t > #<void> > > as expected. > > Maybe someone more knowledgeable than myself could sort out what out of > this is a bug? > > Also, I have to rant a bit about R5RS section 4.3.2. What a mess this is! > To have the literals influenced by bindings outside goes against the spirit > of lexical binding, in my opinion, where the idea is to be able to judge > the outcome of the code from looking at it locally. > > Best regards, > Mikael > > [-- Attachment #1.2: Type: text/html, Size: 5199 bytes --] [-- Attachment #2: matchcoll.scm --] [-- Type: text/x-scheme, Size: 235 bytes --] (use-modules (ice-9 match)) (use-modules (srfi srfi-9)) (define-record-type <foo> (make-foo a b) foo? (a foo-a) (b foo-b)) (match (make-foo 1 2) (($ <foo> a b) (+ a b))) (define $ 'blah) (match (make-foo 1 2) (($ <foo> a b) (+ a b))) [-- Attachment #3: elsetest.scm --] [-- Type: text/x-scheme, Size: 93 bytes --] (display (cond (else #t))) (newline) (define else #f) (display (cond (else #t))) (newline) ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: REPL and load deifferences (was Re: Proposal for a new (ice-9 history)) 2018-10-30 12:20 ` Mikael Djurfeldt @ 2018-10-30 18:01 ` Göran Weinholt 0 siblings, 0 replies; 13+ messages in thread From: Göran Weinholt @ 2018-10-30 18:01 UTC (permalink / raw) To: Mikael Djurfeldt; +Cc: Mark H Weaver, guile-devel Mikael Djurfeldt <mikael@djurfeldt.com> writes: > And, the attachments... > > On Tue, Oct 30, 2018 at 11:21 AM Mikael Djurfeldt <mikael@djurfeldt.com> wrote: > > On Tue, Oct 30, 2018 at 1:55 AM Mikael Djurfeldt <mikael@djurfeldt.com> wrote: > > On Tue, Oct 30, 2018 at 12:55 AM Mark H Weaver <mhw@netris.org> wrote: > >> More precisely, it is a literal >> identifier recognized by 'match' and related macros, in the same sense >> that 'else' and '=>' are literal identifiers recognized by the 'cond' >> macro. >> R5RS section 4.3.2 (Pattern language) specifies how these literal >> identifiers are to be compared with identifiers found in each macro use: >> Identifiers that appear in <literals> are interpreted as literal >> identifiers to be matched against corresponding subforms of the >> input. A subform in the input matches a literal identifier if and >> only if it is an identifier and either both its occurrence in the >> macro expression and its occurrence in the macro definition have >> the same lexical binding, or the two identifiers are equal and both >> have no lexical binding. Guile's documentation says something else: "A literal matches an input expression if the input expression is an identifier with the same name as the literal, and both are unbound(1)." What happened to the case where they have the same binding? > [...] > Incidentally, this does *not* throw an error in master (unless I made > some mistake in this late hour), which then is a bug! There is a catch for R6RS users of Guile with the standard literals 'else', '=>', etc. They are not bound in Guile's standard library, so if a library exports 'else' then the built-in 'cond' no longer recognizes 'else' for users of that library. This is not how other R6RS implementations behave, but IIRC it is somehow expected that Guile behaves this way. It leads to annoying and hard to find bugs. -- Göran Weinholt Debian developer 73 de SA6CJK ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Proposal for a new (ice-9 history) 2018-10-29 14:13 Proposal for a new (ice-9 history) Mikael Djurfeldt 2018-10-29 23:54 ` Mark H Weaver @ 2018-10-30 0:25 ` Mark H Weaver 2018-10-30 1:08 ` Mikael Djurfeldt 1 sibling, 1 reply; 13+ messages in thread From: Mark H Weaver @ 2018-10-30 0:25 UTC (permalink / raw) To: Mikael Djurfeldt; +Cc: guile-devel Mikael Djurfeldt <mikael@djurfeldt.com> writes: > The interface of (value-history) would instead have a lazy-binder > which provides a syntax transformer for every $... actually being > used. The $... identifier would expand into a list-ref into the value > history. A few more suggestions: If I write (define (foo x) (+ $$0 x)) at the repl, then I expect 'foo' to continue to refer to the same entry in the value history, even after the value history is later extended. I'm also a bit concerned about the efficiency implications of expanding these variable references into 'list-ref' calls when the history grows large. If I write a loop that evaluates $$0 a million times, I'd prefer to avoid a million 'list-ref' calls. To address these concerns, I'd like to suggest a slightly different approach: * $0, $1, ... would continue to be ordinary variable bindings in (value-history), as they are now. * The 'count' in 'save-value-history' would be made into a top-level variable in (ice-9 history). * $$0, $$1, $$2, ... would be handled by a lazy-binder, providing a syntax transformer that looks at the value of 'count' at macro expansion time, and expands into the appropriate variable reference $N. For example, if $5 is the most recent value, $$0 would expand into $5 instead of (list-ref ...). This would eliminate my concerns over efficiency. What do you think? Mark ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Proposal for a new (ice-9 history) 2018-10-30 0:25 ` Proposal for a new (ice-9 history) Mark H Weaver @ 2018-10-30 1:08 ` Mikael Djurfeldt 2018-10-30 6:20 ` Mark H Weaver 0 siblings, 1 reply; 13+ messages in thread From: Mikael Djurfeldt @ 2018-10-30 1:08 UTC (permalink / raw) To: Mark H Weaver; +Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 2463 bytes --] On Tue, Oct 30, 2018 at 1:26 AM Mark H Weaver <mhw@netris.org> wrote: > Mikael Djurfeldt <mikael@djurfeldt.com> writes: > > > The interface of (value-history) would instead have a lazy-binder > > which provides a syntax transformer for every $... actually being > > used. The $... identifier would expand into a list-ref into the value > > history. > > A few more suggestions: > > If I write (define (foo x) (+ $$0 x)) at the repl, then I expect 'foo' > to continue to refer to the same entry in the value history, even after > the value history is later extended. > Well, this could be interpreted in two ways. What I expect is that $$0 always refers to the last entry of the value history, even if it has been extended, such that $$0 will evaluate to new values as new values are pushed onto value history. This is also the effect we get if $$0 expands to (list-ref value-history 0). > > I'm also a bit concerned about the efficiency implications of expanding > these variable references into 'list-ref' calls when the history grows > large. If I write a loop that evaluates $$0 a million times, I'd prefer > to avoid a million 'list-ref' calls. > Maybe this is a Microsoft-style argument, but do we really expect users to use value history in that way? If so, I guess value-history could be stored in a dynamically enlarged vector. > To address these concerns, I'd like to suggest a slightly different > approach: > > * $0, $1, ... would continue to be ordinary variable bindings in > (value-history), as they are now. > > * The 'count' in 'save-value-history' would be made into a top-level > variable in (ice-9 history). > (This (count) is what I had in mind for $<N>: $<N> -> (list-ref value-history (- count <N>)) ) > * $$0, $$1, $$2, ... would be handled by a lazy-binder, providing a > syntax transformer that looks at the value of 'count' at macro > expansion time, and expands into the appropriate variable > reference $N. > > For example, if $5 is the most recent value, $$0 would expand into $5 > instead of (list-ref ...). This would eliminate my concerns over > efficiency. > > What do you think? > This would then have the problem that $$0 would get a more complex meaning: It would mean "the most recent result at the time of macro expansion" rather than "the most recent result". If efficiency really is a concern, I would expect that vector references would be rather efficient after compilation. Best regards, Mikael [-- Attachment #2: Type: text/html, Size: 3692 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Proposal for a new (ice-9 history) 2018-10-30 1:08 ` Mikael Djurfeldt @ 2018-10-30 6:20 ` Mark H Weaver 2018-10-30 13:59 ` Mikael Djurfeldt 0 siblings, 1 reply; 13+ messages in thread From: Mark H Weaver @ 2018-10-30 6:20 UTC (permalink / raw) To: Mikael Djurfeldt; +Cc: guile-devel Hi Mikael, Mikael Djurfeldt <mikael@djurfeldt.com> writes: > On Tue, Oct 30, 2018 at 1:26 AM Mark H Weaver <mhw@netris.org> wrote: > > Mikael Djurfeldt <mikael@djurfeldt.com> writes: > > > The interface of (value-history) would instead have a lazy-binder > > which provides a syntax transformer for every $... actually being > > used. The $... identifier would expand into a list-ref into the value > > history. > > A few more suggestions: > > If I write (define (foo x) (+ $$0 x)) at the repl, then I expect 'foo' > to continue to refer to the same entry in the value history, even after > the value history is later extended. > > Well, this could be interpreted in two ways. What I expect is that $$0 > always refers to the last entry of the value history, even if it has > been extended, such that $$0 will evaluate to new values as new values > are pushed onto value history. I can see why it's a natural interpretation, but in practice this seems far less useful to me. I very often write procedures that reference values from the value history. In almost every case I can think of, I want those references to continue to refer to the same value in the future. If $$N has your preferred semantics, then it would almost always be a mistake to refer to $$N from within a procedure body. What use cases do you have in mind that would benefit from your preferred semantics for $$N? I can think of one case: it would enable writing procedures that magically operate on the most recent REPL result, or possibly the last two REPL results, to avoid having to pass them in explicitly as arguments. To support this use case, we could export a procedure from (ice-9 history) to fetch the Nth most recent value. Are there other realistic use cases that you know about? If you think that this is a sufficiently common use case to justify a special set of abbreviations, perhaps we could have just one or two magic variables to fetch the most recent values at run time? What do other people think? > This is also the effect we get if $$0 expands to (list-ref value-history 0). > > I'm also a bit concerned about the efficiency implications of expanding > these variable references into 'list-ref' calls when the history grows > large. If I write a loop that evaluates $$0 a million times, I'd prefer > to avoid a million 'list-ref' calls. > > Maybe this is a Microsoft-style argument, but do we really expect > users to use value history in that way? I do, FWIW. It's not uncommon for me to compute a value at the REPL, write a procedure that uses the value I just computed, possibly build more procedures on top of that, and then evaluate expressions that call the procedures repeatedly, e.g. from within loops. That said, I don't want to overstate the concerns about efficiency. I acknowledge that it's not very important either way. > If so, I guess value-history could be stored in a dynamically enlarged > vector. It would certainly help for efficiency, but it raises another issue, namely that we would need to think about thread safety issues. If a procedure that refers to $$N is entered at the REPL and then evaluated in another thread, the $$N could evaluate to garbage shortly after the value-history vector is enlarged, unless all accesses to $$N are serialized using a mutex. There's also another issue that just came to mind: multiple concurrent REPLs. Each REPL should have its own history, I think. Modern Guile offers REPL servers, which listen for network connections and spawn a new REPL thread for every incoming connection. We also have cooperative REPL servers that enable multiple REPLs within a single thread using cooperative threading, to avoid thread safety issues. Those require a procedure to be called periodically, and are intended for single-threaded programs based on event loops. It would be good to think about how to fix (ice-9 history) to properly support multiple concurrent REPLs in the same process. What do you think? Mark ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Proposal for a new (ice-9 history) 2018-10-30 6:20 ` Mark H Weaver @ 2018-10-30 13:59 ` Mikael Djurfeldt 2018-10-31 16:49 ` Mikael Djurfeldt 0 siblings, 1 reply; 13+ messages in thread From: Mikael Djurfeldt @ 2018-10-30 13:59 UTC (permalink / raw) To: Mark H Weaver; +Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 5255 bytes --] On Tue, Oct 30, 2018 at 7:21 AM Mark H Weaver <mhw@netris.org> wrote: > Hi Mikael, > > Mikael Djurfeldt <mikael@djurfeldt.com> writes: > > > On Tue, Oct 30, 2018 at 1:26 AM Mark H Weaver <mhw@netris.org> wrote: > > > > Mikael Djurfeldt <mikael@djurfeldt.com> writes: > > > > > The interface of (value-history) would instead have a lazy-binder > > > which provides a syntax transformer for every $... actually being > > > used. The $... identifier would expand into a list-ref into the value > > > history. > > > > A few more suggestions: > > > > If I write (define (foo x) (+ $$0 x)) at the repl, then I expect 'foo' > > to continue to refer to the same entry in the value history, even after > > the value history is later extended. > > > > Well, this could be interpreted in two ways. What I expect is that $$0 > > always refers to the last entry of the value history, even if it has > > been extended, such that $$0 will evaluate to new values as new values > > are pushed onto value history. > > I can see why it's a natural interpretation, but in practice this seems > far less useful to me. I very often write procedures that reference > values from the value history. In almost every case I can think of, I > want those references to continue to refer to the same value in the > future. If $$N has your preferred semantics, then it would almost > always be a mistake to refer to $$N from within a procedure body. > > What use cases do you have in mind that would benefit from your > preferred semantics for $$N? > > I can think of one case: it would enable writing procedures that > magically operate on the most recent REPL result, or possibly the last > two REPL results, to avoid having to pass them in explicitly as > arguments. To support this use case, we could export a procedure from > (ice-9 history) to fetch the Nth most recent value. > > Are there other realistic use cases that you know about? > I actually don't have other use-cases other than using value-history in expressions on the command line. My only concern is about the complexity of the semantics. I don't have very strong objections to the semantics you suggest, though. But note, again, that your semantics depends on macro expansion time, such that, e.g., if one would be crazy enough to put this in a file and load it in, then it would behave entirely differently. However, my feeling is that if one really wanted to do real programming against value-history, then the (ice-9 history) module should export suitable selectors with well-defined semantics. Your argument that you find it useful that the value referred to becomes fixed at macro expansion time is sufficient to me to accept it, but let's hear what other people think about it. Note that this issue is independent of whether we use bindings in a module or a list. The list-ref version would simply be a reference relative to "count", and your value would be fixed as per your requested semantics. > If you think that this is a sufficiently common use case to justify a > special set of abbreviations, perhaps we could have just one or two > magic variables to fetch the most recent values at run time? > No, I think that if we implement backward references, then we should be able to pick any value. One or two would be frustrating in many situations. Another possible syntax would be that $-1 refers to the most recent value, and then we could have $-2, $-3, etc. It would all be consistent if value history started out with $0 = ... . Dunno. > > If so, I guess value-history could be stored in a dynamically enlarged > > vector. > > It would certainly help for efficiency, but it raises another issue, > namely that we would need to think about thread safety issues. If a > procedure that refers to $$N is entered at the REPL and then evaluated > in another thread, the $$N could evaluate to garbage shortly after the > value-history vector is enlarged, unless all accesses to $$N are > serialized using a mutex. > > There's also another issue that just came to mind: multiple concurrent > REPLs. Each REPL should have its own history, I think. Modern Guile > offers REPL servers, which listen for network connections and spawn a > new REPL thread for every incoming connection. We also have cooperative > REPL servers that enable multiple REPLs within a single thread using > cooperative threading, to avoid thread safety issues. Those require a > procedure to be called periodically, and are intended for > single-threaded programs based on event loops. It would be good to > think about how to fix (ice-9 history) to properly support multiple > concurrent REPLs in the same process. > > What do you think? > You raise an important issue. Since every REPL runs with its own dynamic state, perhaps a par of fluids would help? Ive noticed Ludovic's (ice-9 vlist) which, as a functional datastructure, would mesh well with a fluid. At the same time it at least partially addresses your concern regarding efficiency since at least the most recent history values would be accessed at O(1). So, history would be stored as a vlist in a fluid and $... references would expand to vlist-ref. What do you think? Is it a problem that this would drag in many modules at start-up? [-- Attachment #2: Type: text/html, Size: 6679 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Proposal for a new (ice-9 history) 2018-10-30 13:59 ` Mikael Djurfeldt @ 2018-10-31 16:49 ` Mikael Djurfeldt 2018-11-02 13:35 ` Mikael Djurfeldt 0 siblings, 1 reply; 13+ messages in thread From: Mikael Djurfeldt @ 2018-10-31 16:49 UTC (permalink / raw) To: Mark H Weaver; +Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 291 bytes --] On Tue, Oct 30, 2018 at 2:59 PM Mikael Djurfeldt <mikael@djurfeldt.com> wrote: > > Is it a problem that this would drag in many modules at start-up? > I checked. It turns out that all modules used by (ice-9 vlist) are loaded anyway. (Otherwise, (language cps intmap) is an option too. :-) [-- Attachment #2: Type: text/html, Size: 603 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Proposal for a new (ice-9 history) 2018-10-31 16:49 ` Mikael Djurfeldt @ 2018-11-02 13:35 ` Mikael Djurfeldt 2018-11-02 14:02 ` Mikael Djurfeldt 0 siblings, 1 reply; 13+ messages in thread From: Mikael Djurfeldt @ 2018-11-02 13:35 UTC (permalink / raw) To: Mark H Weaver; +Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 4933 bytes --] I've thought some more about this. What this is about is a need to refer to previous values in value history in a relative way rather than referring specifically to some historic value. First a simple (and perhaps not so useful) example, where we use Heron's method to compute the square root of 9 (where $ refers to the last value): scheme@(guile-user)> 1 $1 = 1 scheme@(guile-user)> (/ (+ $ (/ 9 $)) 2.0) $2 = 5.0 scheme@(guile-user)> (/ (+ $ (/ 9 $)) 2.0) $3 = 3.4 scheme@(guile-user)> (/ (+ $ (/ 9 $)) 2.0) $4 = 3.023529411764706 scheme@(guile-user)> (/ (+ $ (/ 9 $)) 2.0) $5 = 3.00009155413138 scheme@(guile-user)> (/ (+ $ (/ 9 $)) 2.0) $6 = 3.000000001396984 scheme@(guile-user)> (/ (+ $ (/ 9 $)) 2.0) $7 = 3.0 We also have the more common case that we are debugging a program and need to inspect the output, e.g (where $$0 = $ and $$1 is the value before $).: scheme@(guile-user)> (foo 1) $1 = #<some-object> scheme@(guile-user)> (get-bar $$0) $2 = ... scheme@(guile-user)> (get-baz $$1) $3 = ... scheme@(guile-user)> (foo 2) $4 = #<some-object> scheme@(guile-user)> (get-bar $$0) $5 = ... scheme@(guile-user)> (get-baz $$1) $6 = ... The point is that we can use readline's value history to pick earlier lines with minor or no editing, i.e. we don't need to say $4 in the last two selectors. Maybe even more importantly, using relative value history references is conceptually easier, since we don't have to pay attention to the index of the value in value history. Mark also mentioned a use case where procedures are successively built up using values from value history. We have now discussed three different problems associated with such an extension: 1. Naming and name collisions We currently have a GDB-compatible naming scheme where values are named $1, $2 etc. It is then natural to extend this to the full GDB value history naming scheme, introducing $, $$ and $$<N>. $ collides with the auxilliary syntactic keyword $ in (ice-9 match). Unfortunately, the interpretation of literals in syntax-rules and syntax-case macros are influenced by bindings in the environment where macros are used (according to R5RS 4.3.2) such that value history $ will disrupt $ matching in (ice-9 match). This can be solved by using different naming. Mark suggested that $ could be renamed to $$. I suggested a naming scheme where $-1, $-2 could be used for relative refrences. Chicken scheme uses #[N] and this could also be extended by letting negative numbers be relative references. However, I'm thinking that it is a bit awkward to have to consider all possible uses of names when selecting this naming scheme. I would very much prefer to let a GDB user feel at home. Is there a way for names to coexist? Well, we have the module system. Ideally, I think that value history lookups should be done in a special top level environment which is associated with the REPL. Top level bindings in the Scheme environment should have precedence. Now, instead, (ice-9 history) has a hack which patches (value-history) into every environment we visit. Given this situation, is there still a way to use the module system to give (ice-9 match) $ precedence? There is. Göran Weinholt has pointed out that other Scheme implementations tend to export their auxilliary keywords. If we export $ like this: --8<---------------cut here---------------start------------->8--- (define-module (ice-9 match) #:export (match match-lambda match-lambda* match-let match-let* match-letrec) #:replace ($)) [...] (define misplaced (let ((m (lambda (x) (format #f "Misplaced aux keyword ~A" x)))) (lambda (x) (syntax-case x () (_ (identifier? x) (syntax-violation #f (m (syntax->datum x)) x)) ((_ ...) (syntax-violation #f (m (car (syntax->datum x))) x)))))) (define-syntax $ misplaced) [...] (include-from-path "ice-9/match.upstream.scm") --8<---------------cut here---------------start------------->8--- then (ice-9 match) will gracefully replace $ in (value-history) and match will work as expected. A good idea would be to define *all* auxilliary keywords to `misplaced' above, according to what Göran has said. That is independent of the issue of name collisions. If $ is replaced this way, the user can still write $$0 for that value. 2. Threading and multiple REPL:s I have suggested to store value history in a fluid and use a functional data type for the value history. That way we avoid race conditions. 3. Efficiency If value history is stored in a vlist (a module which is used in the core of Guile), much of it, particularly the most recent values, will be accessed at O(1). If we care less about efficiency and want something lean and simple, then ordinary lists will do. Comments? [-- Attachment #2: Type: text/html, Size: 6056 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Proposal for a new (ice-9 history) 2018-11-02 13:35 ` Mikael Djurfeldt @ 2018-11-02 14:02 ` Mikael Djurfeldt 0 siblings, 0 replies; 13+ messages in thread From: Mikael Djurfeldt @ 2018-11-02 14:02 UTC (permalink / raw) To: Mark H Weaver; +Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 1458 bytes --] On Fri, Nov 2, 2018 at 2:35 PM Mikael Djurfeldt <mikael@djurfeldt.com> wrote: > Given this situation, is there still a way to use the module system to > give (ice-9 match) $ precedence? There is. Göran Weinholt has pointed out > that other Scheme implementations tend to export their auxilliary keywords. > If we export $ like this: > > --8<---------------cut here---------------start------------->8--- > (define-module (ice-9 match) > #:export (match > [...] > match-letrec) > #:replace ($)) > [...] > --8<---------------cut here---------------start------------->8--- > > then (ice-9 match) will gracefully replace $ in (value-history) and match > will work as expected. A good idea would be to define *all* auxilliary > keywords to `misplaced' above, according to what Göran has said. That is > independent of the issue of name collisions. > Just to avoid misunderstanding. Of course, to avoid the hard-to-find bugs which Göran talked about, auxilliary keywords should be exported the normal way (through export). That way name collisions will be reported. Possibly that is what we should do here as well, also for $, such that there is a warning when (ice-9 match) is imported. Also, what we really wanted to say is not that (ice-9 match) $ is "replacing". We rather wanted to say that (value-history) $ is "deferring", but there is no way to do that in the module system right now. [-- Attachment #2: Type: text/html, Size: 2167 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2018-11-02 14:02 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-10-29 14:13 Proposal for a new (ice-9 history) Mikael Djurfeldt 2018-10-29 23:54 ` Mark H Weaver 2018-10-30 0:55 ` Mikael Djurfeldt 2018-10-30 10:21 ` REPL and load deifferences (was Re: Proposal for a new (ice-9 history)) Mikael Djurfeldt 2018-10-30 12:20 ` Mikael Djurfeldt 2018-10-30 18:01 ` Göran Weinholt 2018-10-30 0:25 ` Proposal for a new (ice-9 history) Mark H Weaver 2018-10-30 1:08 ` Mikael Djurfeldt 2018-10-30 6:20 ` Mark H Weaver 2018-10-30 13:59 ` Mikael Djurfeldt 2018-10-31 16:49 ` Mikael Djurfeldt 2018-11-02 13:35 ` Mikael Djurfeldt 2018-11-02 14:02 ` Mikael Djurfeldt
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).