Re: [racket-users] Sending Closures to Places
On 03/08/2015 07:22, Neil Van Dyke wrote: Michael Titke wrote on 08/03/2015 12:50 AM: Perhaps /quote/ and /eval/ would do the job? That is the usual way to treat Scheme code as data and data as Scheme code. Eval might indeed be the perfect solution this time, iff every other conceivable alternative has been rejected. :) Shameless link to PSA on the topic of eval: http://lists.racket-lang.org/users/archive/2014-July/063597.html Suggestions for other forms for PSA are welcome: http://lists.racket-lang.org/users/archive/2014-July/063618.html Neil V. On a second thought you would even need to serialize the data graph (let's just call it string) and unstring it on the other side with the infamous /read/. You could just send a dot rkt file there ... -- 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] Optimizing closures
I see, thanks for the explanations, Matthew. So that's the kind of things that are simple in principle, but more complicated than one would like in practice then. Good luck with your experiments! On Fri, Jul 31, 2015 at 10:02 PM, Matthew Flatt mfl...@cs.utah.edu wrote: At Fri, 31 Jul 2015 18:56:15 +0100, Laurent wrote: On Fri, Jul 31, 2015 at 5:40 PM, Matthew Flatt mfl...@cs.utah.edu wrote: At Fri, 31 Jul 2015 15:03:53 +0100, Laurent wrote: I don't really understand why `in-range` makes such a difference. It looks like the kind of sequence iterator is tested at each step, whereas I was expecting it to be tested only at the beginning of the loop, since this sequence iterator kind can't change from one iteration to the next, right? Hence, I was expecting the `in-range` (and actually all other `in-*`) issue to appear only inside nested loops, where some loops are started many times (thus requiring many iterator kind tests). Right: The `in-*` functions tell `for` what kind of step operations to inline into the loop (after an initial guard that confirms that it has a number, list, etc., to iterate through). Otherwise, there's a run-time dispatch to take each step, which is usually more significant than a run-time dispatch to set up the loop. Apparently the optimizer is looking very specifically for `in-range`. This: (define my-in-range in-range) (time (for ([x (my-in-range 4000)]) (+ x 3))) is as slow as not using `in-range` at all, which I find rather strange. It's really the `for` macro that recognizes `in-*`. The expansion of a `for` form is too complex for the optimizer to see through the levels of dispatching. Giving macros more power to interact with the optimizer is a long-term goal, but it's beyond the things that Racket macros can do right now. By run-time dispatch, do you mean that the check of which kind the argument is is done at each iteration? No... Isn't it possible to test this only on the very first iteration? Then the rest of the loop should be as fast as with `in-range`. The fact that `add1` should be used for stepping is determined once at the start of the loop. Since that determination is dynamic, however, the call to `add1` is not static in the bytecode, and so the JIT doesn't inline `add1`. Some JITs would detect that `add1` turns out to be the stepping function on the first iteration, when the loop is compiled. Then, the JIT would optimistically generate a faster path for future iterations where `add1` turns out to be the stepping function. It's possible that Racket's JIT could do that and achieve some intermediate performance --- not as fast as `in-range` but better than current performance without `in-range`. I'll have to try some experiments. -- 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] Sending Closures to Places
2015-08-02 19:12 GMT+02:00 Konstantin Weitz konstantin.we...@gmail.com: I'm trying to write a distributed racket program using [places][0]. From my current understanding, this means that I have to send data to each place over a channel using the `place-channel-put` function, which can send any value accepted by `place-message-allowed?`. I would like to send closures over a channel, unfortunately, closures are not accepted by `place-message-allowed?`. Is there any way to serialize a closure into a value accepted by a channel, and then deserialize it on the other side of the channel? How many lambda expressions are we talking about? If the number is limited you can defined custom closures. Whether or not the following is practical I will leave up to you to decide :-) Consider this program. (define x 3) (define f (lambda (y) (+ x y))) (f 4) Annotate the free variables of the lambda-expression. (define x 3) (define f (lambda (y) (+ x y))) ; x is free (f 4) Define an explicit closure struct and a helper to access free variables. (struct closure (code free) #:prefab) The code field will refer to a closed (no free variables) version of f and free is a vector of the values of the free variables at the time the closure was created. The idea is that we want to replace (lambda (y) (+ x y)) with (closure f_closed (vector x)). A little helper to access the free variables: (define (free-ref cl i) (vector-ref (closure-free cl) i)) Now define a closed (no free variables) version of f: (define f_closed (lambda (cl y) (let ((x (free-ref cl 0))) (+ x y We can now rewrite the lambda expression into a closure allocation. The full program is now: (struct closure (code free) #:prefab) (define (free-ref cl i) (vector-ref (closure-free cl) i)) (define f_closed (lambda (cl y) (let ((x (free-ref cl 0))) (+ x y (define x 3) (define f (closure f_closed (vector x))) (f 4) Note that the structure is a prefab structure in order to be a legal message. At this point there is a complication: * f_closed is not an allowed message * (f 4) fails since the closure structure is not applicable The first point is solved by sending the name of f_closed as a symbol. One could use eval to change it back to a function, but a hash table will do: (define closed-functions-ht (make-hasheq (list (cons 'f_closed f_closed (define (get-closed-function name) (hash-ref closed-functions-ht name (λ _ (error 'app no closed function of that name ~a name The other can unfortunately not be solved by turning the structure into an applicable struct, since prefab structures can't have properties. Therefore we need to introduce a construct app that knows how to invoke closures. (define-syntax-rule (app cl arg ...) ((get-closed-function (closure-code cl)) cl arg ...)) The entire program is now: #lang racket (struct closure (code free) #:prefab) (define (free-ref cl i) (vector-ref (closure-free cl) i)) (define f_closed (lambda (cl y) (let ((x (free-ref cl 0))) (+ x y (define closed-functions-ht (make-hasheq (list (cons 'f_closed f_closed (define (get-closed-function name) (hash-ref closed-functions-ht name (λ _ (error 'app no closed function of that name ~a name (define-syntax-rule (app cl arg ...) ((get-closed-function (closure-code cl)) cl arg ...)) (define x 3) (define f (closure 'f_closed (vector x))) (app f 4) The value of f is: f '#s(closure f_closed #(3)) and that value is an allowed message. The standard higher operations such as map and apply do not know about the special calling convention of f, so (map f '(1 2 3)) will not work. It is no big deal though, since wrapping f in a lambda works: (map (λ (x) (app f x)) '(1 2 3)) '(4 5 6) To make this solution practical one could introduce a macro Lambda that turns (Lambda (x) (y) (+ x y)) into (closure 'closed1 (vector x))) and at the same time lifts (define closed1 (lambda (cl y) (let ((x (free-ref cl 0))) (+ x y to the top of the program. An ambitious solution would also use free-vars from syntax/free-vars to determine the free variables automatically. /Jens Axel -- 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] Sending Closures to Places
Note that the web-server has support for serializable closures: http://docs.racket-lang.org/web-server-internal/closure.html I think they are the practical choice. /Jens Axel 2015-08-03 12:29 GMT+02:00 Jens Axel Søgaard jensa...@soegaard.net: 2015-08-02 19:12 GMT+02:00 Konstantin Weitz konstantin.we...@gmail.com: I'm trying to write a distributed racket program using [places][0]. From my current understanding, this means that I have to send data to each place over a channel using the `place-channel-put` function, which can send any value accepted by `place-message-allowed?`. I would like to send closures over a channel, unfortunately, closures are not accepted by `place-message-allowed?`. Is there any way to serialize a closure into a value accepted by a channel, and then deserialize it on the other side of the channel? How many lambda expressions are we talking about? If the number is limited you can defined custom closures. Whether or not the following is practical I will leave up to you to decide :-) Consider this program. (define x 3) (define f (lambda (y) (+ x y))) (f 4) Annotate the free variables of the lambda-expression. (define x 3) (define f (lambda (y) (+ x y))) ; x is free (f 4) Define an explicit closure struct and a helper to access free variables. (struct closure (code free) #:prefab) The code field will refer to a closed (no free variables) version of f and free is a vector of the values of the free variables at the time the closure was created. The idea is that we want to replace (lambda (y) (+ x y)) with (closure f_closed (vector x)). A little helper to access the free variables: (define (free-ref cl i) (vector-ref (closure-free cl) i)) Now define a closed (no free variables) version of f: (define f_closed (lambda (cl y) (let ((x (free-ref cl 0))) (+ x y We can now rewrite the lambda expression into a closure allocation. The full program is now: (struct closure (code free) #:prefab) (define (free-ref cl i) (vector-ref (closure-free cl) i)) (define f_closed (lambda (cl y) (let ((x (free-ref cl 0))) (+ x y (define x 3) (define f (closure f_closed (vector x))) (f 4) Note that the structure is a prefab structure in order to be a legal message. At this point there is a complication: * f_closed is not an allowed message * (f 4) fails since the closure structure is not applicable The first point is solved by sending the name of f_closed as a symbol. One could use eval to change it back to a function, but a hash table will do: (define closed-functions-ht (make-hasheq (list (cons 'f_closed f_closed (define (get-closed-function name) (hash-ref closed-functions-ht name (λ _ (error 'app no closed function of that name ~a name The other can unfortunately not be solved by turning the structure into an applicable struct, since prefab structures can't have properties. Therefore we need to introduce a construct app that knows how to invoke closures. (define-syntax-rule (app cl arg ...) ((get-closed-function (closure-code cl)) cl arg ...)) The entire program is now: #lang racket (struct closure (code free) #:prefab) (define (free-ref cl i) (vector-ref (closure-free cl) i)) (define f_closed (lambda (cl y) (let ((x (free-ref cl 0))) (+ x y (define closed-functions-ht (make-hasheq (list (cons 'f_closed f_closed (define (get-closed-function name) (hash-ref closed-functions-ht name (λ _ (error 'app no closed function of that name ~a name (define-syntax-rule (app cl arg ...) ((get-closed-function (closure-code cl)) cl arg ...)) (define x 3) (define f (closure 'f_closed (vector x))) (app f 4) The value of f is: f '#s(closure f_closed #(3)) and that value is an allowed message. The standard higher operations such as map and apply do not know about the special calling convention of f, so (map f '(1 2 3)) will not work. It is no big deal though, since wrapping f in a lambda works: (map (λ (x) (app f x)) '(1 2 3)) '(4 5 6) To make this solution practical one could introduce a macro Lambda that turns (Lambda (x) (y) (+ x y)) into (closure 'closed1 (vector x))) and at the same time lifts (define closed1 (lambda (cl y) (let ((x (free-ref cl 0))) (+ x y to the top of the program. An ambitious solution would also use free-vars from syntax/free-vars to determine the free variables automatically. /Jens Axel -- -- Jens Axel Søgaard -- 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
Re: [racket-users] continuing after a user break
It does seem useful. It would require some thought because the exception handler cannot escape until there is no possibility of resuming which seems like it would have UI implications. This would also cause some REPL interactions to behave differently when they are in the break-resumable context (notably those involving continuations and related things). But I agree it seems worth thinking about. Since it's been 7 days and I've not made any more progress than that, I guess that the best I can offer is advice if someone else wants to give it a try. Robby On Mon, Jul 27, 2015 at 5:48 PM, John Carmack jo...@oculus.com wrote: Any chance that could make it in as a DrRacket feature? Seems likely to have moderately broad utility. Out of curiosity, what programming environment do the core Racket devs use when programming Racket? I quite like DrRacket for my projects that are only a few files, but it doesn't seem to be aimed at large scale work. -Original Message- From: Matthew Flatt [mailto:mfl...@cs.utah.edu] Sent: Monday, July 27, 2015 2:43 PM To: John Carmack Cc: Racket Users Subject: Re: [racket-users] continuing after a user break At Mon, 27 Jul 2015 19:32:32 +, John Carmack wrote: Is it possible to continue execution after a ^b user break in DrRacket (not debugging)? It would often be useful to be able to ^b, print some global state, set some flags, and continue running. The `exn:break` exception record includes a `continuation` field. An exception handler can apply that continuation to resume from the point of the break. A significant limitation is that the handler has to be installed with `call-with-continuation-handler` or `uncaught-exception-handler`. If any `with-handlers` is in effect, it will catch any continuation and escape to the `with-handlers` form, at which point the continuation in `exn:break` cannot be applied (because it's an escape-only continuation). #lang racket (let ([orig (uncaught-exception-handler)]) (uncaught-exception-handler (lambda (exn) (if (exn:break? exn) (begin (printf continuing...\n) ((exn:break-continuation exn))) (orig exn) (let loop () (loop)) -- 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. -- 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] Macro that does substitution
On Wed, Jul 29, 2015 at 9:30 AM, Matthias Felleisen matth...@ccs.neu.edu wrote: On Jul 29, 2015, at 7:50 AM, Klaus Ostermann wrote: Thanks, Matthew and Matthias. The service on this mailing list is incredible! I know it is not cbn because it is local, but a better name didn't come to my mind and it is what I need to solve my problem. It's not about locality, the problem is that it runs the thunks at the wrong time. Example: (let ((x (/ 1 0))) ((lambda (y) (displayln `(hello world))) x)) in CBN would _first_ show hello-world and then raise the exception but your let-cbn will raise the exception first and never display anything on the output port. I'm confused. Why would this raise an exception? x is never in strict position, as `y` is unused in the lambda. But, I could simply be missing something, and if so, please ignore. :) -- http://www.apgwoz.com -- 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] Macro that does substitution
Correct. There should never be an exception because the value never ends up in a strict position. -- Matthias On Aug 3, 2015, at 12:44 PM, Andrew Gwozdziewycz apg...@gmail.com wrote: On Wed, Jul 29, 2015 at 9:30 AM, Matthias Felleisen matth...@ccs.neu.edu wrote: On Jul 29, 2015, at 7:50 AM, Klaus Ostermann wrote: Thanks, Matthew and Matthias. The service on this mailing list is incredible! I know it is not cbn because it is local, but a better name didn't come to my mind and it is what I need to solve my problem. It's not about locality, the problem is that it runs the thunks at the wrong time. Example: (let ((x (/ 1 0))) ((lambda (y) (displayln `(hello world))) x)) in CBN would _first_ show hello-world and then raise the exception but your let-cbn will raise the exception first and never display anything on the output port. I'm confused. Why would this raise an exception? x is never in strict position, as `y` is unused in the lambda. But, I could simply be missing something, and if so, please ignore. :) -- http://www.apgwoz.com -- 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] eval PSA (was Sending Closures to Places)
On 2015-08-03 01:22AM, Neil Van Dyke wrote: Eval might indeed be the perfect solution this time, iff every other conceivable alternative has been rejected. :) Shameless link to PSA on the topic of eval: http://lists.racket-lang.org/users/archive/2014-July/063597.html Suggestions for other forms for PSA are welcome: If people knew *why* and *how* to avoid eval, wouldn't they already be doing it? To be useful to your target audience, I think you *need* to back this up with a link to supporting documentation. I'd be looking for: - A *brief* high-level statement of why eval causes problems: maybe something like this? I'm sure there are better statements out there... eval takes code which was constructed in one context and assigns meaning to it in a different context. This can cause the code to have an unexpected meaning, or fail to work altogether. It can also cause security problems (if you pass it code from an untrusted source) or be unnecessarily slow (evaluating code at runtime which could have been fixed at compile time). - Rules of thumb for how to decide what to use instead, and when eval might be ok. This answer (http://stackoverflow.com/a/2571549/2426692) suggests asking: - Do I really need eval or does the compiler/evaluator already do what I want? - Does the code really need to be constructed at runtime or can it be constructed earlier? - Will funcall, reduce, or apply work instead? - Concrete examples of where beginners tend to use eval and how to code them without it. This is sort of the same as the previous one, but I like to see a short overview of the whole strategy by itself, so I would put the examples separately, e.g. HTDP has a *nice* clear overview of the design recipe, whereas HTDP 2e has no place where you can go for a quick refresher of what were the steps of the design recipe again? - That's my two cents. I always see these sorts of things getting brushed off as unhelpful or even patronizing, so I think you want to go out of your way to make it easy to dig into it and reach successively deeper levels of understanding. --Josh -- 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] eval PSA (was Sending Closures to Places)
On eval in dynamic languages generally and in Racket specifically http://blog.racket-lang.org/2011/10/on-eval-in-dynamic-languages-generally.html Posted by Matthew Flatt http://blog.racket-lang.org/2011/10/on-eval-in-dynamic-languages-generally.html 2015-08-03 13:32 GMT+02:00 Josh Grams j...@qualdan.com: On 2015-08-03 01:22AM, Neil Van Dyke wrote: Eval might indeed be the perfect solution this time, iff every other conceivable alternative has been rejected. :) Shameless link to PSA on the topic of eval: http://lists.racket-lang.org/users/archive/2014-July/063597.html Suggestions for other forms for PSA are welcome: If people knew *why* and *how* to avoid eval, wouldn't they already be doing it? To be useful to your target audience, I think you *need* to back this up with a link to supporting documentation. I'd be looking for: - A *brief* high-level statement of why eval causes problems: maybe something like this? I'm sure there are better statements out there... eval takes code which was constructed in one context and assigns meaning to it in a different context. This can cause the code to have an unexpected meaning, or fail to work altogether. It can also cause security problems (if you pass it code from an untrusted source) or be unnecessarily slow (evaluating code at runtime which could have been fixed at compile time). - Rules of thumb for how to decide what to use instead, and when eval might be ok. This answer (http://stackoverflow.com/a/2571549/2426692) suggests asking: - Do I really need eval or does the compiler/evaluator already do what I want? - Does the code really need to be constructed at runtime or can it be constructed earlier? - Will funcall, reduce, or apply work instead? - Concrete examples of where beginners tend to use eval and how to code them without it. This is sort of the same as the previous one, but I like to see a short overview of the whole strategy by itself, so I would put the examples separately, e.g. HTDP has a *nice* clear overview of the design recipe, whereas HTDP 2e has no place where you can go for a quick refresher of what were the steps of the design recipe again? - That's my two cents. I always see these sorts of things getting brushed off as unhelpful or even patronizing, so I think you want to go out of your way to make it easy to dig into it and reach successively deeper levels of understanding. --Josh -- 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. -- -- Jens Axel Søgaard -- 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] upcoming v6.2.1
On Jul 29, 2015, at 08:16, Matthew Flatt mfl...@cs.utah.edu wrote: We're preparing a v6.2.1 release, which will go out before August 10. The v6.2.1 build will be a small set of patches to v6.2, i.e., not derived from the current development branch. The patches are for the HtDP teaching languages. The main patch for v6.2.1 is to add an option to restore the old output format for booleans and the empty list in *SL --- to print as true, false, and empty, instead of the new style of #true, #false, and '() that was enabled in v6.2. Classes using DrRacket will not necessarily need v6.2.1. In particular, the latest version of HtDP2e uses the new v6.2 output format, while the names true, false, and empty can still be used in programs. The output change can be a problem, however, for teachers who have other material that depends on the old output format (and that is not easily updated). So, if your class does not need the old printing style, feel free to use the current v6.2 release. Can the fix for the regression I reported (on 7/14) get backported to the 6.2 branch? This is the minimal repro: #lang racket (define dup (lambda (f) (f f))) (lambda () (let ([rep (lambda (f) (f f))]) (dup rep))) -- 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.