Re: [racket-users] generalised set! in Racket
Hi all, Thanks to all replies, at the moment I would tend to agree that generalised `set!` might not be such a great idea after all: - The notion of 'place' is essentially a pointer to a memory location, but it is not the first-class citizen: the following expressions are not equivalent: (let ((x (aref v 5))) (set! x 100)) and (set! (aref v 5) 100), and it might be the place for confusion. - The syntax part of it, `(set! (what-ever ...) new-value)`, however, I don't mind: `set!` is a special form/macro after all, not a procedure. No one would demand the procedural clarity from `let` or `define`. The question is rather if it worth having yet another special form. Summarising the points above, what if instead of `set!` there is a more general abstraction 'location': it can hold the value, the value might be re-set, but on its own it is just a memory location. Basically, it's Racket's `box`. But the interesting twists would be getting the locations from mutable objects (like vectors and arrays). Something like this: (define v (vector 0 1 2 3 4 5)) (vector-ref v 2) ;; - 2 this gets you the value ;; Hypothetical procedure vector-loc (vector-loc v 2) ;; - (boxed 2) (location-set! (vector-loc v 2) 200) v ;; - (0 1 200 3 4 5) (let ((x (vector-loc v 3))) (location-set! x 300)) v ;; - (0 1 200 300 4 5) A quick implementation for vectors might look as follows: #lang racket (require racket/generic) (define-generics location (location-ref location) (location-set! location new-value)) (struct vecloc (v ind) #:methods gen:location ((define (location-ref location) (vector-ref (vecloc-v location) (vecloc-ind location))) (define (location-set! location new-value) (vector-set! (vecloc-v location) (vecloc-ind location) new-value (define (vector-loc v ind) (vecloc v ind)) (define v (vector 0 1 2 3 4 5)) (location-set! (vector-loc v 2) 200) (let ((x (vector-loc v 3))) (location-set! x 300)) Wouldn't it resolve all the mentioned concerns? Now we can have named locations and we don't introduce any new syntax. What I don't know is how efficient this implementation is. Best regards, Alexey On 1 July 2015 at 03:29, Matthias Felleisen matth...@ccs.neu.edu wrote: On Jun 30, 2015, at 6:43 PM, George Neuner wrote: On 6/30/2015 5:34 PM, 'John Clements' via Racket Users wrote: On Jun 30, 2015, at 8:10 AM, Alexey Cherkaev alexey.cherk...@gmail.com wrote: ... wouldn't it be beneficial to have such a generalised 'set!' system-wide? I understand that Racket focusses more on immutable structures, but there are still vectors and hash-tables which are inherently mutable and still have their niche. This style of set! seems like a bad idea to me. Specifically, one of the basic ideas of algebraic languages is that programs are compositional. Specifically, if I write (a (b x) c), then the meaning of this term depends on the meanings of a, (b x), and c. That is, I can combine these three values to get the result. Generalized set! breaks this intuition. Specifically, (set! (aref x 0 1) 13) does not depend on the value of (aref x 0 1). Rather, it pulls apart this term and uses its subterm’s meanings. Put differently, this is lvalues. I know, I know, I sound like a pure-functional snooty-poo. Don't confuse source syntax with what goes on under the hood - compilers for imperative languages often go to great lengths to transform programs into more functional forms. Search for value numbering and static single assignment for more information. [Those aren't the only functionalizing transformations, but they are the most commonly used.] Moreover, assignment per se is not incompatible with composition - that's just semantics. On real hardware, assignment is all you have: binding is implemented as assignment to a (possibly) new location. Tail recursion is an important case of invisibly binding new values to the same locations (i.e. assigning to the control variables of an imperative loop). John knows these things. His advisor co-invented SSA and preached the imperative-compilers-are-functional while he was in grad school. I know, I was there and watched, and I know the guy. I am sure it all sank in. What you fail to see is that it's just semantics is a way of saying why bother programming in languages such as Racket or ML or Coq. It's all assignment statements on the machine anyway. As we know from many years of experience of course is that this statement makes no sense to a good programmer. There are huge differences. And what John is getting at is that the language (as is) carries its meaning and its pragmatics on its sleeves. The very moment you introduce the kind of generalized assignment statement you lose this kind of clarity that comes with the language. So let's all be happy now and program in ASM. It's assignments anyway and LHS values are lovely for the
Re: [racket-users] generalised set! in Racket
On Jul 1, 2015, at 4:27 AM, Alexey Cherkaev alexey.cherk...@gmail.com wrote: Hi all, Thanks to all replies, at the moment I would tend to agree that generalised `set!` might not be such a great idea after all: The notion of 'place' is essentially a pointer to a memory location, but it is not the first-class citizen: the following expressions are not equivalent: (let ((x (aref v 5))) (set! x 100)) and (set! (aref v 5) 100), and it might be the place for confusion. The syntax part of it, `(set! (what-ever ...) new-value)`, however, I don't mind: `set!` is a special form/macro after all, not a procedure. No one would demand the procedural clarity from `let` or `define`. The question is rather if it worth having yet another special form. The syntax part of it is what srfi/17 does, and anyone who requires srfi/17 hopefully understands that it’s another special form, and that the (what-ever …) is not actually an expression, and hopes that people reading the code will also understand that. Because of the first point, it’s best that it’s in a separate library like srfi/17, not available by default, because that avoids confusion unless you require srfi/17 on purpose. Summarising the points above, what if instead of `set!` there is a more general abstraction 'location’: Side note: Such a `location` abstraction doesn’t have to be all about mutability. There is a purely functional version of this concept in Jack Firth's `lenses` package, which says that lenses are functions that take a data structure and returns two values; the first being the “view,” or the value at that location, and the second being the “context” of that value, represented as a function that acts as a functional “setter,” and these lenses are functional and compose-able. http://pkg-build.racket-lang.org/doc/lenses@lenses/index.html https://github.com/jackfirth/lenses Also, because lenses return two values, they don't have to allocate a new structure every time, which (I think) means slightly better performance. -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
On Jun 30, 2015, at 6:43 PM, George Neuner wrote: On 6/30/2015 5:34 PM, 'John Clements' via Racket Users wrote: On Jun 30, 2015, at 8:10 AM, Alexey Cherkaev alexey.cherk...@gmail.com wrote: ... wouldn't it be beneficial to have such a generalised 'set!' system-wide? I understand that Racket focusses more on immutable structures, but there are still vectors and hash-tables which are inherently mutable and still have their niche. This style of set! seems like a bad idea to me. Specifically, one of the basic ideas of algebraic languages is that programs are compositional. Specifically, if I write (a (b x) c), then the meaning of this term depends on the meanings of a, (b x), and c. That is, I can combine these three values to get the result. Generalized set! breaks this intuition. Specifically, (set! (aref x 0 1) 13) does not depend on the value of (aref x 0 1). Rather, it pulls apart this term and uses its subterm’s meanings. Put differently, this is lvalues. I know, I know, I sound like a pure-functional snooty-poo. Don't confuse source syntax with what goes on under the hood - compilers for imperative languages often go to great lengths to transform programs into more functional forms. Search for value numbering and static single assignment for more information. [Those aren't the only functionalizing transformations, but they are the most commonly used.] Moreover, assignment per se is not incompatible with composition - that's just semantics. On real hardware, assignment is all you have: binding is implemented as assignment to a (possibly) new location. Tail recursion is an important case of invisibly binding new values to the same locations (i.e. assigning to the control variables of an imperative loop). John knows these things. His advisor co-invented SSA and preached the imperative-compilers-are-functional while he was in grad school. I know, I was there and watched, and I know the guy. I am sure it all sank in. What you fail to see is that it's just semantics is a way of saying why bother programming in languages such as Racket or ML or Coq. It's all assignment statements on the machine anyway. As we know from many years of experience of course is that this statement makes no sense to a good programmer. There are huge differences. And what John is getting at is that the language (as is) carries its meaning and its pragmatics on its sleeves. The very moment you introduce the kind of generalized assignment statement you lose this kind of clarity that comes with the language. So let's all be happy now and program in ASM. It's assignments anyway and LHS values are lovely for the heart-ware purist :-) -- Matthias -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
On Jun 30, 2015, at 5:34 PM, 'John Clements' via Racket Users racket-users@googlegroups.com wrote: Specifically, one of the basic ideas of algebraic languages is that programs are compositional. Specifically, if I write (a (b x) c), then the meaning of this term depends on the meanings of a, (b x), and c. That is, I can combine these three values to get the result. Generalized set! breaks this intuition. Specifically, (set! (aref x 0 1) 13) does not depend on the value of (aref x 0 1). Rather, it pulls apart this term and uses its subterm’s meanings. Actually, this makes a lot of sense to me and is probably the best argument I’ve heard for why lvalues can be a bad idea. (and some time ago I read the discussion on SRFI 17, just for fun looking at the reasoning on both sides) Thanks! -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
Racket does have 'make-set!-transformer' that allows you to define syntax that cooperates with 'set!'. I think that might work if you are defining your own datatype. Have you seen that? Thanks, Dave On 06/30/2015 11:10 AM, Alexey Cherkaev wrote: Hi Alexander, Thanks for your reply: I had something similar in mind (maybe I should check out math/array). I was just wondering if there was something more Racket-like (it still feels that SRFI is somewhat 'foreign' hack). And my last question remains: wouldn't it be beneficial to have such a generalised 'set!' system-wide? I understand that Racket focusses more on immutable structures, but there are still vectors and hash-tables which are inherently mutable and still have their niche. Best regards, Alexey On 29 June 2015 at 18:36, Alexander D. Knauth alexan...@knauth.org mailto:alexan...@knauth.org wrote: On Jun 29, 2015, at 5:56 AM, Alexey Cherkaev alexey.cherk...@gmail.com mailto:alexey.cherk...@gmail.com wrote: For example, I was thinking of defining syntax to access my implementation of multidimensional arrays as (define-syntax aref (syntax-rules (set!) [(set! (aref ?a ?i ...) ?v) (array-set! ?a ?i ... ?v)] [(aref ?a ?i ...) (array-ref ?a ?i ...)])) but obviously it won't work now as `set!` expects the `id` not an expression (`syntax-id-rules` won't work either as `aref` is not an `id`). #lang racket (require srfi/17 math/array) (define (aref a . is) (array-ref a (list-vector is))) (set! (setter aref) (λ (a . is+v) (match-define (list is ... v) is+v) (array-set! a (list-vector is) v))) (define a (mutable-array #[#[1 2] #[3 4]])) (aref a 0 1) (set! (aref a 0 1) 20) (aref a 0 1) If you wanted, you could also define your own version of set! that does what you want, which (I think) you would need to do if you needed aref to be a macro. -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com mailto:racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
I have implemented generalized `set!` in Racket before, as a cute exploratory exercise, but I haven't found a sufficiently compelling benefit of generalized `set!`. The closest I've imagined to benefit of generalized `set!`: let's say you had really terse but nice referencing syntax for complex objects (records, collections), and you wanted to make the assignment lvalue syntax look the same as the rvalue syntax. For example, how in some language we might have both of: p = a[x][y] a[x][y] = p However, with Racket obviously coming from the Scheme tradition, Racket is not about the terse syntax (not until you get into DSLs, which is different). I don't see sufficient benefit to complicating the semantics of the language just to make `(set! (vector-ref v 0) 42)` equivalent to `(vector-set! v 0 42)`. If you want to get into OO-like generalization, one could come up with a scenario in which generalized `set!` could be used, but offhand I can't think of an example that couldn't be done with a more conventional use of OO objects and methods. If someone has a great scenario for how generalized `set!` wins, I'd be interested in seeing it. (For example, maybe there's a win in some scenario of syntax transformation, in which you wind up with a `(set! ACCESSOR VALUE)` pattern, and for some reason it's easy to get there but hard to get to `(SETTER-PROC OBJ VALUE)`? Just a bad speculative example; you'd need to go further.) Neil V. -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
Hi Alexander, Thanks for your reply: I had something similar in mind (maybe I should check out math/array). I was just wondering if there was something more Racket-like (it still feels that SRFI is somewhat 'foreign' hack). And my last question remains: wouldn't it be beneficial to have such a generalised 'set!' system-wide? I understand that Racket focusses more on immutable structures, but there are still vectors and hash-tables which are inherently mutable and still have their niche. Best regards, Alexey On 29 June 2015 at 18:36, Alexander D. Knauth alexan...@knauth.org wrote: On Jun 29, 2015, at 5:56 AM, Alexey Cherkaev alexey.cherk...@gmail.com wrote: For example, I was thinking of defining syntax to access my implementation of multidimensional arrays as (define-syntax aref (syntax-rules (set!) [(set! (aref ?a ?i ...) ?v) (array-set! ?a ?i ... ?v)] [(aref ?a ?i ...) (array-ref ?a ?i ...)])) but obviously it won't work now as `set!` expects the `id` not an expression (`syntax-id-rules` won't work either as `aref` is not an `id`). #lang racket (require srfi/17 math/array) (define (aref a . is) (array-ref a (list-vector is))) (set! (setter aref) (λ (a . is+v) (match-define (list is ... v) is+v) (array-set! a (list-vector is) v))) (define a (mutable-array #[#[1 2] #[3 4]])) (aref a 0 1) (set! (aref a 0 1) 20) (aref a 0 1) If you wanted, you could also define your own version of set! that does what you want, which (I think) you would need to do if you needed aref to be a macro. -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
As the mentioned SRFI states it: This is a proposal to allow procedure calls that evaluate to the value of a location to be used to /set/ the value of the location, when used as the first operand of |set!|. The term location is only used in the introductory part but for those who know the way behind the scenes it clearly refers to the concept of memory addresses of current register machines. By not introducing the domain of memory addresses (where you might as well SETF your graphics card ROM, EFI boot loaders and other registered beings in that real address space that is then virtualized but still contains your call stack) they push you into the world of nameless concepts which would be the same as lambda forms without define. Just try this in your favorite clean Scheme environment but don't call it algorithmic language then. With generics it is possible to define the necessary methods for set! - one such method exists in GOOPS (sorry!) which is able to set slots of objects by accessor. The name or identifier isn't gone yet but its sequence of symbols or syntax just looks awful: (define point (make point #:x 1 #:y 2)) (x point) = 1 (set! (x point) 2) (x point) = 2 With common sense (and not behind scenes) /x/ denotes both the value as well as a method to set it. Other programming systems use the dot syntax which works slightly better, e.g. /point.x/./ / Generics and a generalized /set!/ have been en vogue in the 80s as far as I know and have then been substituted by message passing interfaces where you usually define your own getters and setters for each and every variable which might behind the scenes turn out to be stored on a server on the next floor or it might just be your favorite terminal emulation dimming some little lights called pixels. Back to the generalized /set!/: it leaves you in a world of invisible pointers or location which might even be called concepts. When one starts thinking in abstract concepts and goes from concept to concept one might end up where one has to invent new words to grab them mentally. This is what Latin is good for. But a generalized set! might just do away with that little rest of language that remained in the Algorithmic Language Scheme. I think I'm going to purge some /set!/ methods from VSI/goops. Regards, Michael On 29/06/2015 11:56, Alexey Cherkaev wrote: Hi all, Common Lisp has a very useful idiom of SETF that can set values to arbitrary places. For example, one can set (1 2)-th item of an array A as: (SETF (AREF A 1 2) 20.0d0) Scheme preferred way is to use `*-set!` procedures. However, sometimes it is inconvenient. For example, if I want to swap two elements in the array/vector, I would like to use `swap`: (define-syntax swap (syntax-rules () ((swap ?place1 ?place2 ?tmp) (begin (set! ?tmp ?place1) (set! ?place1 ?place2) (set! ?place2 ?place1) But it will only work for vectors if `set!` can act as CL's SETF on generalised places, such as (swap (vector-ref v 5) (vector-ref v 3) tmp) SRFI-17 contains the definition of such a `set!` and I can use it from there (AFAIR Racket supports it). I was wondering if there is more Racket-way of doing this? And is there maybe a reason why `set!` wasn't given the same power as SETF? For example, I was thinking of defining syntax to access my implementation of multidimensional arrays as (define-syntax aref (syntax-rules (set!) [(set! (aref ?a ?i ...) ?v) (array-set! ?a ?i ... ?v)] [(aref ?a ?i ...) (array-ref ?a ?i ...)])) but obviously it won't work now as `set!` expects the `id` not an expression (`syntax-id-rules` won't work either as `aref` is not an `id`). Regards, Alexey -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
On Jun 30, 2015, at 8:10 AM, Alexey Cherkaev alexey.cherk...@gmail.com wrote: Hi Alexander, Thanks for your reply: I had something similar in mind (maybe I should check out math/array). I was just wondering if there was something more Racket-like (it still feels that SRFI is somewhat 'foreign' hack). And my last question remains: wouldn't it be beneficial to have such a generalised 'set!' system-wide? I understand that Racket focusses more on immutable structures, but there are still vectors and hash-tables which are inherently mutable and still have their niche. This style of set! seems like a bad idea to me. Specifically, one of the basic ideas of algebraic languages is that programs are compositional. Specifically, if I write (a (b x) c), then the meaning of this term depends on the meanings of a, (b x), and c. That is, I can combine these three values to get the result. Generalized set! breaks this intuition. Specifically, (set! (aref x 0 1) 13) does not depend on the value of (aref x 0 1). Rather, it pulls apart this term and uses its subterm’s meanings. Put differently, this is lvalues. I know, I know, I sound like a pure-functional snooty-poo. John -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
On 6/30/2015 5:34 PM, 'John Clements' via Racket Users wrote: On Jun 30, 2015, at 8:10 AM, Alexey Cherkaev alexey.cherk...@gmail.com wrote: ... wouldn't it be beneficial to have such a generalised 'set!' system-wide? I understand that Racket focusses more on immutable structures, but there are still vectors and hash-tables which are inherently mutable and still have their niche. This style of set! seems like a bad idea to me. Specifically, one of the basic ideas of algebraic languages is that programs are compositional. Specifically, if I write (a (b x) c), then the meaning of this term depends on the meanings of a, (b x), and c. That is, I can combine these three values to get the result. Generalized set! breaks this intuition. Specifically, (set! (aref x 0 1) 13) does not depend on the value of (aref x 0 1). Rather, it pulls apart this term and uses its subterm’s meanings. Put differently, this is lvalues. I know, I know, I sound like a pure-functional snooty-poo. Don't confuse source syntax with what goes on under the hood - compilers for imperative languages often go to great lengths to transform programs into more functional forms. Search for value numbering and static single assignment for more information. [Those aren't the only functionalizing transformations, but they are the most commonly used.] Moreover, assignment per se is not incompatible with composition - that's just semantics. On real hardware, assignment is all you have: binding is implemented as assignment to a (possibly) new location. Tail recursion is an important case of invisibly binding new values to the same locations (i.e. assigning to the control variables of an imperative loop). George -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
On Jun 30, 2015, at 3:43 PM, George Neuner gneun...@comcast.net wrote: that's just semantics. XD -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
On 06/30/2015 07:27 PM, 'John Clements' via Racket Users wrote: On Jun 30, 2015, at 3:43 PM, George Neuner gneun...@comcast.net wrote: that's just semantics. XD Let me expound a bit on John's pure-functional snooty-poo reply. Semantics - what programs mean - is everything. Exactly how they're compiled, interpreted, JITted, transformed, optimized, and otherwise put through the meat grinder to make something useful, is secondary. If a certain feature would void a property that *humans* find extremely helpful when reasoning about programs, there had better be really good motivation for it. Carry on. Neil ⊥ -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] generalised set! in Racket
On Jun 29, 2015, at 5:56 AM, Alexey Cherkaev alexey.cherk...@gmail.com wrote: For example, I was thinking of defining syntax to access my implementation of multidimensional arrays as (define-syntax aref (syntax-rules (set!) [(set! (aref ?a ?i ...) ?v) (array-set! ?a ?i ... ?v)] [(aref ?a ?i ...) (array-ref ?a ?i ...)])) but obviously it won't work now as `set!` expects the `id` not an expression (`syntax-id-rules` won't work either as `aref` is not an `id`). #lang racket (require srfi/17 math/array) (define (aref a . is) (array-ref a (list-vector is))) (set! (setter aref) (λ (a . is+v) (match-define (list is ... v) is+v) (array-set! a (list-vector is) v))) (define a (mutable-array #[#[1 2] #[3 4]])) (aref a 0 1) (set! (aref a 0 1) 20) (aref a 0 1) If you wanted, you could also define your own version of set! that does what you want, which (I think) you would need to do if you needed aref to be a macro. -- You received this message because you are subscribed to the Google Groups Racket Users group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.