[racket-users] Re: code reflection

2017-10-17 Thread George Neuner
On Mon, 16 Oct 2017 17:11:53 -0400, Matthias Felleisen
 wrote:

>> On Oct 16, 2017, at 2:17 PM, George Neuner  wrote:
>
>> Lisp's macros are ... I won't say easier to use correctly, because
>> they aren't ... but IMO they are easier to understand and think about
>> because the input is just a tree of normal Lisp objects that can be
>> manipulated using normal Lisp functions.  No dichotemy of "this is
>> syntax" vs "that is data", and no bridges to cross between two
>> different representations.
>
>
>Lisp macros are easier than Racket’s in the same way that it 
>was so much easier to write procedures in ASM than in Pascal. 
>It was so much easier to manipulate bit patterns directly, 
>why bother calling some Integer and others Chars. 

I think maybe you overlooked where I said "use correctly".
Non-hygienic macros are much easier to write ... but they are also
much easier to f_ up and do something unexpected when used.

In any case, it was not my intent to start a religious war here.
Scheme's macros work as they do for a reason [and yes! I do know the
reason].  I don't necessarily have to like it though, nor do I have to
say that I do.

I have read "Fear of Macros".  Long ago in fact.  I don't fear macros
at all ... I'm a [getting old] compiler geek and what I fear is to
lack understanding of what's going on under the hood.  Lisp is pretty
transparent about it's IR internals ... Scheme not so much.

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] Re: code reflection

2017-10-17 Thread David Storrs
On Tue, Oct 17, 2017 at 2:36 AM, Konrad Hinsen
 wrote:
>  I never got
> around to work on this seriously, both because of the 24-hour-per-day limit
> that I cannot seem to get rid of,

When you figure that one out, don't forget to open source your
solution, okay?  Or, at the very least, patent it and sell licenses.
I'll be first in line.

-- 
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] Re: code reflection

2017-10-16 Thread Ben Greenman
> Greg, if you're reading this...any chance you might expand FoM?

In the meantime, the "Syntax Parse Examples" package is always
accepting contributions:
http://docs.racket-lang.org/syntax-parse-example/index.html#%28part._.The_.Examples%29

-- 
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] Re: code reflection

2017-10-16 Thread Matthias Felleisen

> On Oct 16, 2017, at 5:26 PM, David Storrs  wrote:
> 
> On Mon, Oct 16, 2017 at 5:11 PM, Matthias Felleisen
>  wrote:
>> 
>> You speak of personal failing, and I think that’s incorrect.
>> We are missing a good introduction to syntax and friends.
> 
> George Neuner, you might want to look at Greg Hendershott's "Fear of
> Macros"  (http://www.greghendershott.com/fear-of-macros/).  I found it
> to be a very good introduction to syntax and to macros in general.  I
> just wish he hadn't stopped before covering syntax-parse, as I did not
> find the reference docs as helpful for that one as he did.
> 
> Greg, if you're reading this...any chance you might expand FoM?


Thanks, I am well aware of Greg’s work even though I forget it too often. 
My introductory lectures to the macro system at the Racket summer school 
ended up following the same path (w/o remembering Greg’s write-up). 

@ George: Yes, do read Greg’s post. And you may find the lectures Matthew
and I gave at the Racket school useful too. 

Still, we ought to be able to do much better — 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] Re: code reflection

2017-10-16 Thread David Storrs
On Mon, Oct 16, 2017 at 5:11 PM, Matthias Felleisen
 wrote:
>
> You speak of personal failing, and I think that’s incorrect.
> We are missing a good introduction to syntax and friends.

George Neuner, you might want to look at Greg Hendershott's "Fear of
Macros"  (http://www.greghendershott.com/fear-of-macros/).  I found it
to be a very good introduction to syntax and to macros in general.  I
just wish he hadn't stopped before covering syntax-parse, as I did not
find the reference docs as helpful for that one as he did.

Greg, if you're reading this...any chance you might expand FoM?

Dave



>
> But having said that, I need to contradict this one:
>
>> Lisp's macros are ... I won't say easier to use correctly, because
>> they aren't ... but IMO they are easier to understand and think about
>> because the input is just a tree of normal Lisp objects that can be
>> manipulated using normal Lisp functions.  No dichotemy of "this is
>> syntax" vs "that is data", and no bridges to cross between two
>> different representations.
>
>
> Lisp macros are easier than Racket’s in the same way that it
> was so much easier to write procedures in ASM than in Pascal.
> It was so much easier to manipulate bit patterns directly,
> why bother calling some Integer and others Chars.
>
> — 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.

-- 
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] Re: code reflection

2017-10-16 Thread Matthias Felleisen




> On Oct 16, 2017, at 2:17 PM, George Neuner  wrote:


You speak of personal failing, and I think that’s incorrect. 
We are missing a good introduction to syntax and friends. 

But having said that, I need to contradict this one: 

> Lisp's macros are ... I won't say easier to use correctly, because
> they aren't ... but IMO they are easier to understand and think about
> because the input is just a tree of normal Lisp objects that can be
> manipulated using normal Lisp functions.  No dichotemy of "this is
> syntax" vs "that is data", and no bridges to cross between two
> different representations.


Lisp macros are easier than Racket’s in the same way that it 
was so much easier to write procedures in ASM than in Pascal. 
It was so much easier to manipulate bit patterns directly, 
why bother calling some Integer and others Chars. 

— 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.


[racket-users] Re: code reflection

2017-10-16 Thread George Neuner

Hi all, 

Thanks to everyone who replied.  I apologize for posting and vanishing
... a family emergency on Saturday took me away for the weekend.

David:
Thank you for the exposition about your task scheduler.  I have
something similar, a (thread safe) priority queue based on data/heap,
although it isn't persistent like yours.  This "time definition" code
was an attempt to make using it easier / more natural.

Ryan: 
You are probably correct that this job doesn't need such a complex
macro ... probably one to parse out times, plus some purpose functions
would suffice.  But the question about how to reference the
environment from a macro is tangential to the task and I really thank
you for trying to answer it.   I'm going to have to study your
solution for a while as I'm not sure I yet understand it.
 
  -


I have written 2 compilers from scratch, and I have no trouble using
non-hygienic macros in Lisp, or syntax-rules, syntax-case  in Scheme.
But I start to get queasy when the task exceeds what can be done
easily with syntax-rules or syntax-case.

I can't easily articulate my problem with syntax: the best I can come
up with is that it is, in a real sense, a black box.  There is an API
to manipulate it ... but no real understanding of exactly what is
being manipulated or how the functions tie together.  For me the
documentation talks a lot but doesn't seem to say very much.  
[I recognize that this is a personal failing ... obviously other
people are able to figure it out, so the problem must be with me.]

Lisp's macros are ... I won't say easier to use correctly, because
they aren't ... but IMO they are easier to understand and think about
because the input is just a tree of normal Lisp objects that can be
manipulated using normal Lisp functions.  No dichotemy of "this is
syntax" vs "that is data", and no bridges to cross between two
different representations.



Thanks to everybody.  I need to go now and study what Ryan did.

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] Re: code reflection

2017-10-15 Thread David Storrs
Given the quality and depth of prior comments in this thread, I'm a
little reluctant to chime in.  I suppose, however, that people on this
list tend to be forgiving and maybe my much less elegant solution will
be helpful, at least as inspiration.  This solution is not originally
intended for the problem you're asking about, but it can be used for
your problem.

Effectively, you want to carry state forward in time from one function
to another.  I had a somewhat related problem in that I wanted to
schedule tasks for the future.  Obviously, I needed a job queue.
Fortunately, Racket has one:
https://docs.racket-lang.org/job-queue/index.html  (Hat tip to Jay
McCarthy)

I wanted to be able to schedule them for the future.  One way to do
that would be to make up a job like this:

(thunk
   (sleep 60)
   (do stuff))

...and then hand it to the worker queue.  It would run in its own
thread so as not to block the main thread, so scheduling issue solved.
The problem with this is that the jobs are not durable; if the Racket
process crashed then all the jobs would go up in a puff of magic smoke
with no way to recover them.

Ah, durability, you say?  Isn't that what the 'D' in DB stands for?
(Answer: no, it's not.)  Okay, database sounds good.  So, I created a
'tasks' table that would store details about the job that I wanted to
run and when to run them.  Periodically a thread would check the
table, grab a job that was eligible, and run it. It would have been
nice to be able to shove straight Racket code in there, but that would
have required 'evil' -- I mean, 'eval'.  Instead, I stuffed in a JSON
blob that looked (in part) like this:

{  "task" : "sync-file-list-for-team", "args" : [ "team name"] }

Then I did the ugly part:  I created a global variable.

Said variable was a hash table (yes, yes, John, I know:  structs are
better than hashes for most things.  You  convinced me in the general
case, but for this I really did need something free-form) that looked
like so:

(hash   "sync-file-list" (lambda (args-list) ...stuff...))

You can recover the function by doing:

(define task  (...database query that retrieves the JSON object and
parses it into a hash...))

; 'task' is something like (hash "task" "sync-file-list "args" (list
"team name"))

(define func (function-from task)) ; take the value of the "task" key,
look it up in the global jumptable, retrieve the lambda stored there
(define args (args-from task))  ; get the list from the task hash
(func args) ; run it


Anything that wants to schedule a task can now do this:

(require "lib/workers.rkt")

(define/contract (sync-file-list-for-team lst)
  (-> list? any)
...do stuff...)

(register-functions sync-file-list-for-team)

(add-task
db-connection
#:task sync-file-list-for-team
#:args (list "team name")
#:delay 90 ; will not run for *at least* 90 seconds.  No guarantee
about when it *will* run
#:priority 10  ; default is 0, bigger is higher priority
)

Or, if you'd prefer to be able to pass fancier state:

(register-functions (list "extra-args-for-a-func" (thunk (list 'x 'y
(thunk 7)
(define (a-func lst)
(define extra-args ((function-from (hash "task" "extra-args-for-a-thunk"
; extra-args is now (list 'x 'y (thunk 7))
...)

The tasks are now durable, since they're in the DB.  If the Racket
process crashes then the jumptable will go away, but as long as your
register-functions calls are at top level then the jumptable will be
rebuilt when the module is next loaded.


Like I said, this isn't exactly the problem you were asking about --
there's no macros involved, for one thing -- and it's way less elegant
than the other solutions that people have been offering.  Despite
that, I've found it useful and so I thought I'd share.

On Sat, Oct 14, 2017 at 7:37 PM, 'John Clements' via Racket Users
 wrote:
> Lovely! I was thinking along these lines, but you hit it out of the park. 
> Sounds like you must be avoiding some really important task!
>
> John
>
>> On Oct 14, 2017, at 11:31, Ryan Culpepper  wrote:
>>
>> On 10/14/2017 05:01 AM, George Neuner wrote:
>>> On 10/14/2017 3:00 AM, Jack Firth wrote:

So is there a way ... from normal code ... to get at the locals of
functions higher in the call chain?  Or at least the immediate
caller?
Some reflective capability that I haven't yet discovered?


 I'm not sure if there's a way to do that, but I'm wondering if what you 
 want to do can be achieved more simply with plain functions and a very 
 small macro wrapper. In particular, I suspect putting too much logic in 
 the macro is what led you to eval which is the root of all evil. From what 
 I can tell there shouldn't be any need at all for eval or any sort of 
 dynamic runtime compilation to do things like what you're describing. 
 Could you give a few more details about your use case? Ideally with some 
 

Re: [racket-users] Re: code reflection

2017-10-14 Thread 'John Clements' via Racket Users
Lovely! I was thinking along these lines, but you hit it out of the park. 
Sounds like you must be avoiding some really important task!

John

> On Oct 14, 2017, at 11:31, Ryan Culpepper  wrote:
> 
> On 10/14/2017 05:01 AM, George Neuner wrote:
>> On 10/14/2017 3:00 AM, Jack Firth wrote:
>>> 
>>>So is there a way ... from normal code ... to get at the locals of
>>>functions higher in the call chain?  Or at least the immediate
>>>caller?
>>>Some reflective capability that I haven't yet discovered?
>>> 
>>> 
>>> I'm not sure if there's a way to do that, but I'm wondering if what you 
>>> want to do can be achieved more simply with plain functions and a very 
>>> small macro wrapper. In particular, I suspect putting too much logic in the 
>>> macro is what led you to eval which is the root of all evil. From what I 
>>> can tell there shouldn't be any need at all for eval or any sort of dynamic 
>>> runtime compilation to do things like what you're describing. Could you 
>>> give a few more details about your use case? Ideally with some example code 
>>> illustrating the problem?
>> Basically, this is a sort of Unix at-like function for flexible scheduling.  
>> It takes an expression containing dates, times, certain keywords and 
>> arbitrary numeric expressions, and it produces seconds since the epoch.  
>> Code is attached - hope it survives posting to the list.  It should be 
>> runnable as is.
>> What led me to eval originally was wanting to reference arbitrary 
>> functions/variables from the runtime environment.  I'd like to be able to say
>> things like:
>>(let [(y 42)] (schedule (at now + y mins) ...))
>> and similar involving top-level defined functions [which already works with 
>> eval].
>> I know that eval is not needed if I generate inline code rather than having 
>> the macro invoke a normal function.  But that is complicated by having to 
>> deal with free form expressions: they can have internal references between 
>> things which are not necessarily adjacent.  It is doable, but at some 
>> expense and not very cleanly.
>> I started out going the "compile" route - just generating inline code.  But 
>> as more functionality was added, that became unwieldy. So I switched to a 
>> runtime function. Right now the assoc list code is overly complex [so please 
>> ignore it] - it is there as a debugging tool until I get everything working 
>> exactly right.
> 
> Your example above shows that you want the `at` macro to accept a mixture of 
> Racket expressions and syntax that you interpret. If you want to accept 
> Racket expressions, you must leave them as syntax objects. Once you flatten 
> them with `syntax->datum`, there is *no way* to *correctly* recover their 
> meaning.
> 
> Here's my attempt to adapt the HtDP design recipe to a scaled-down version of 
> this problem.
> 
> First, let's think about the syntax (grammar) that `at` should accept. Let's 
> call it a Time. What are some reasonable Times?
> 
>  now
>  now + 30 ;; means 30 seconds
>  today
>  tomorrow + 20 mins
>  now + x mins + (/ ms 1000) secs
>  "2017-10-14 1:17:25" + 30 mins
> 
> But there are also some terms that are nonsense as Times:
> 
>  12
>  today + tomorrow
>  now mins
> 
> Let's say (as a place to start) that a Time consists of an absolute reference 
> point (like now or today) and some number of offsets. Here's a grammar:
> 
>  ;; Time = TimeBase {+ TimeExt}*
>  ;; TimeBase = now | today | String[Date]
>  ;; TimeExt = Expr[Real] MaybeUnit
>  ;; MaybeUnit =  | secs | mins
> 
> Let's call the *meaning* of a Time a TimeVal, and let's represent it as a 
> real number of seconds, using the same epoch as (current-seconds).
> 
>  ;; A TimeVal is a real number of seconds
>  ;; using the same epoch as (current-seconds)
> 
> The meaning of TimeBase is also a TimeVal. The meanings of TimeExt and 
> MaybeUnit are both Real (they are duration and durations scales; they have no 
> epoch).
> 
> Now to translate that plan to Racket.
> 
> First, turn keywords like `now` into "illegal use" macro definitions:
> 
>  (begin-for-syntax
>(define (at-keyword stx)
>  (raise-syntax-error #f "illegal use of `at` keyword" stx)))
>  (define-syntax now at-keyword)
>  (define-syntax today at-keyword)
>  (define-syntax secs at-keyword)
>  (define-syntax mins at-keyword)
> 
> Then define syntax classes for the nonterminals in the grammar. I'll also 
> define an `expr` attribute to compute the meaning of each term. For example, 
> the syntax class for TimeBase is
> 
>  (begin-for-syntax
>(define-syntax-class TimeBase
>  #:attributes (expr) ;; expression of TimeVal
>  #:literals (now today)
>  (pattern now
>   #:with expr #'(current-seconds))
>  (pattern today
>   #:with expr #'(today-fun))
>  (pattern s:str
>   #:with expr #'(parse-date-string s
> 
> To avoid complicating the syntax class and also to avoid making the expansion 
> bigger than 

Re: [racket-users] Re: code reflection

2017-10-14 Thread Ryan Culpepper

On 10/14/2017 05:01 AM, George Neuner wrote:


On 10/14/2017 3:00 AM, Jack Firth wrote:


So is there a way ... from normal code ... to get at the locals of
functions higher in the call chain?  Or at least the immediate
caller?
Some reflective capability that I haven't yet discovered?


I'm not sure if there's a way to do that, but I'm wondering if what 
you want to do can be achieved more simply with plain functions and a 
very small macro wrapper. In particular, I suspect putting too much 
logic in the macro is what led you to eval which is the root of all 
evil. From what I can tell there shouldn't be any need at all for eval 
or any sort of dynamic runtime compilation to do things like what 
you're describing. Could you give a few more details about your use 
case? Ideally with some example code illustrating the problem?


Basically, this is a sort of Unix at-like function for flexible 
scheduling.  It takes an expression containing dates, times, certain 
keywords and arbitrary numeric expressions, and it produces seconds 
since the epoch.  Code is attached - hope it survives posting to the 
list.  It should be runnable as is.


What led me to eval originally was wanting to reference arbitrary 
functions/variables from the runtime environment.  I'd like to be able 
to say

things like:

    (let [(y 42)] (schedule (at now + y mins) ...))

and similar involving top-level defined functions [which already works 
with eval].


I know that eval is not needed if I generate inline code rather than 
having the macro invoke a normal function.  But that is complicated by 
having to deal with free form expressions: they can have internal 
references between things which are not necessarily adjacent.  It is 
doable, but at some expense and not very cleanly.


I started out going the "compile" route - just generating inline code.  
But as more functionality was added, that became unwieldy. So I switched 
to a runtime function. Right now the assoc list code is overly complex 
[so please ignore it] - it is there as a debugging tool until I get 
everything working exactly right.


Your example above shows that you want the `at` macro to accept a 
mixture of Racket expressions and syntax that you interpret. If you want 
to accept Racket expressions, you must leave them as syntax objects. 
Once you flatten them with `syntax->datum`, there is *no way* to 
*correctly* recover their meaning.


Here's my attempt to adapt the HtDP design recipe to a scaled-down 
version of this problem.


First, let's think about the syntax (grammar) that `at` should accept. 
Let's call it a Time. What are some reasonable Times?


  now
  now + 30 ;; means 30 seconds
  today
  tomorrow + 20 mins
  now + x mins + (/ ms 1000) secs
  "2017-10-14 1:17:25" + 30 mins

But there are also some terms that are nonsense as Times:

  12
  today + tomorrow
  now mins

Let's say (as a place to start) that a Time consists of an absolute 
reference point (like now or today) and some number of offsets. Here's a 
grammar:


  ;; Time = TimeBase {+ TimeExt}*
  ;; TimeBase = now | today | String[Date]
  ;; TimeExt = Expr[Real] MaybeUnit
  ;; MaybeUnit =  | secs | mins

Let's call the *meaning* of a Time a TimeVal, and let's represent it as 
a real number of seconds, using the same epoch as (current-seconds).


  ;; A TimeVal is a real number of seconds
  ;; using the same epoch as (current-seconds)

The meaning of TimeBase is also a TimeVal. The meanings of TimeExt and 
MaybeUnit are both Real (they are duration and durations scales; they 
have no epoch).


Now to translate that plan to Racket.

First, turn keywords like `now` into "illegal use" macro definitions:

  (begin-for-syntax
(define (at-keyword stx)
  (raise-syntax-error #f "illegal use of `at` keyword" stx)))
  (define-syntax now at-keyword)
  (define-syntax today at-keyword)
  (define-syntax secs at-keyword)
  (define-syntax mins at-keyword)

Then define syntax classes for the nonterminals in the grammar. I'll 
also define an `expr` attribute to compute the meaning of each term. For 
example, the syntax class for TimeBase is


  (begin-for-syntax
(define-syntax-class TimeBase
  #:attributes (expr) ;; expression of TimeVal
  #:literals (now today)
  (pattern now
   #:with expr #'(current-seconds))
  (pattern today
   #:with expr #'(today-fun))
  (pattern s:str
   #:with expr #'(parse-date-string s

To avoid complicating the syntax class and also to avoid making the 
expansion bigger than necessary, factor run-time behavior out into 
helper functions, like `today-fun`:


  ;; today-fun : -> TimeVal
  (define (today-fun)
(define today (current-date))
(find-seconds 0 0 0 (date-day today) (date-month today) (date-year 
today)))


Here's the syntax class for TimeExt. It uses `expr/c` to make sure the 
given Racket expression actually produces a number.


  (begin-for-syntax

Re: [racket-users] Re: code reflection

2017-10-14 Thread George Neuner


On 10/14/2017 3:00 AM, Jack Firth wrote:


So is there a way ... from normal code ... to get at the locals of
functions higher in the call chain?  Or at least the immediate
caller?
Some reflective capability that I haven't yet discovered?


I'm not sure if there's a way to do that, but I'm wondering if what 
you want to do can be achieved more simply with plain functions and a 
very small macro wrapper. In particular, I suspect putting too much 
logic in the macro is what led you to eval which is the root of all 
evil. From what I can tell there shouldn't be any need at all for eval 
or any sort of dynamic runtime compilation to do things like what 
you're describing. Could you give a few more details about your use 
case? Ideally with some example code illustrating the problem?


Basically, this is a sort of Unix at-like function for flexible 
scheduling.  It takes an expression containing dates, times, certain 
keywords and arbitrary numeric expressions, and it produces seconds 
since the epoch.  Code is attached - hope it survives posting to the 
list.  It should be runnable as is.


What led me to eval originally was wanting to reference arbitrary 
functions/variables from the runtime environment.  I'd like to be able 
to say

things like:

   (let [(y 42)] (schedule (at now + y mins) ...))

and similar involving top-level defined functions [which already works 
with eval].


I know that eval is not needed if I generate inline code rather than 
having the macro invoke a normal function.  But that is complicated by 
having to deal with free form expressions: they can have internal 
references between things which are not necessarily adjacent.  It is 
doable, but at some expense and not very cleanly.


I started out going the "compile" route - just generating inline code.  
But as more functionality was added, that became unwieldy. So I switched 
to a runtime function. Right now the assoc list code is overly complex 
[so please ignore it] - it is there as a debugging tool until I get 
everything working exactly right.


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.
#lang racket/base

(require
  (for-syntax racket/base
  racket/format
  racket/pretty
  )

  racket/base
  racket/match
  racket/list
  racket/format
  racket/dict
  racket/date
  racket/port
  )


(provide
 at
 at-time
 month/year
 )


;%%%
#|

allows free form date/time descriptions in
the style of the Unix "at" command. converts
the description into seconds since the Unix
epoch: 1970-01-01 at 00:00hrs.

the resulting seconds value may be converted
into a usable date structure, or passed to
an alarm event for scheduling.

freestanding + operators will be ignored.
for signed values use [+-]?[:digits:]+.

key words:
  "now" = current date/time
  "today"  - at 00hrs
  "tomorrow"   - at 00hrs
  "this-month" - at 00hrs on the 1st
  "next-month" - at 00hrs on the 1st

dates must be entered in -mm-dd format.

times are 24hr format: hours and minutes
are required - seconds are optional.  a
separate AM/PM qualifier can be used to adjust
ambiguous times.

anything not a date, time or keyword will be
evaluated as a racket expression. expressions
may reference variables or functions from the
surrounding code environment.

an expression may be followed immediately by
a unit multiplier.  units may be seconds,
minutes, hours, days, or weeks (or some of
the typical abbreviations for these units).

|#
;%%%


;==
;
;  macro interface - generates call to
;  parsing function at runtime
;
;==

(define-syntax (at stx)
  (let* [
 (input   (cdr (syntax->datum stx)))
 (input   (map ~a input))
 (fnspec  (list 'apply '+ (list* 'at-time input)))
]

(datum->syntax stx fnspec)
))


;%%%


;==
;
;  parse a time/date description
;
;==


(define (at-time #:namespace [ns (current-namespace)] . input)
  (let* [
 (now(current-seconds))
 (today  (current-date))
 (hour12 (* 12 60 60))
 (hour13 (* 13 60 60))
]

(let loop [
   (input  input)
   (output '())
  ]
  
  (match input
  
; done
([? empty?]
 (eprintf "=> ~s~n" (reverse output))
 (map cdr output)
 )


; current time
([list "now" _ ___ ]
 (loop (cdr input) (cons (cons 'now now) output)))


; date (at 00:00:00)
([list (pregexp px-date [list _ 

[racket-users] Re: code reflection

2017-10-14 Thread Jack Firth

>
> So is there a way ... from normal code ... to get at the locals of 
> functions higher in the call chain?  Or at least the immediate caller? 
> Some reflective capability that I haven't yet discovered? 
>

I'm not sure if there's a way to do that, but I'm wondering if what you 
want to do can be achieved more simply with plain functions and a very 
small macro wrapper. In particular, I suspect putting too much logic in the 
macro is what led you to eval which is the root of all evil. From what I 
can tell there shouldn't be any need at all for eval or any sort of dynamic 
runtime compilation to do things like what you're describing. Could you 
give a few more details about your use case? Ideally with some example code 
illustrating the problem?

-- 
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.