[racket] Use of map and eval to evaluate symbol in namespace

256 views
Skip to first unread message

Henry Lenzi

unread,
Jul 26, 2014, 11:12:51 PM7/26/14
to us...@racket-lang.org
#lang racket

#|

Dear Racketeers -

I would like to create a little function
that would write a line of a medical recipe.

I would pass to "read" a shorthand form,
and the program would expand the text. Like so:

When I answer "hctz25" and "30", it would print:
"Hydrochlorothiazide 25mg ----------- 30 pills".

But I'm facing problems related to:
- use of "map" with "eval" in the definition area (namespace issues...)
See below.
|#


(require scheme/base) ; Is this necessary?
(define this-namespace (make-base-namespace))

(define hctz25 "Hydroclorothiazide 25mg")
(define line "-----------")
(define pl "pills")

(define *med-name* 'NIL) ; *med-name* has global scope - this is on purpose
(define *med-name-str* "") ; *med-name-str* has global scope

(define (ask-med-name)
(print "Medication") (newline)
(set! *med-name* (read))
(set! *med-name-str* (symbol->string *med-name*)))

(define *quant* 0) (define *quant-str* " ")

(define (ask-quant)
(print "Quantity") (newline)
(and
(set! *quant* (read)) (unless (number? *quant*) (error "It's not a
number!")))
(set! *quant-str* (number->string *quant*)))

(define (ask)
(ask-med-name)
(ask-quant))
(ask)

#|
Where's the problem?
In the REPL, I can do this:

> (map eval '((eval *med-name*) line *quant-str* pl))
'("Hydrochlorothiazide 25mg" "-----------" "30" "pills")

or this:

> (string-join (map eval '((eval *med-name*) line *quant-str* pl)))

"Hydrochlorothiazide 25mg ----------- 30 pills"


But, because of the namespace issues associated with "eval", I'm not
able to do it in the definition area.

I have no clue as to what the syntax should be.

Thanks for any help.

Henry Lenzi

|#
____________________
Racket Users list:
http://lists.racket-lang.org/users

Pierpaolo Bernardi

unread,
Jul 27, 2014, 12:53:06 AM7/27/14
to Henry Lenzi, users
This is not a case where eval is useful (very few of such cases exist).

Here's a hint:

#lang racket

(define abbreviations
(hash 'hctz25 "Hydroclorothiazide 25mg"
;; more abbreviations here
))

(define (print-a-line med quant)
(printf "~a ---- ~a pills~n"
(hash-ref abbreviations med "uh?")
quant))

then:

> (print-a-line 'hctz25 30)
Hydroclorothiazide 25mg ---- 30 pills


I hope this will get you started

P.

Matthew Butterick

unread,
Jul 27, 2014, 1:38:12 AM7/27/14
to Racket list
The REPL automatically uses the current namespace, which is why you can casually use eval there without specifying a namespace. [1]

But if you're using eval in the definitions window, you need to give it a namespace, otherwise you'll get "unbound identifier" errors.

In this case, the namespace you want is the one you're already in. So rather than using (make-base-namespace), which will give you an new namespace [2], you need a namespace anchor. To make an anchor, put this in your definitions:

(define-namespace-anchor a)

And then to use the anchor, change your `map` to this:

(map (λ(str) (eval str (namespace-anchor->namespace a))) 
    '((eval *med-name*) line *quant-str* pl) )

And it works.

PS I assume you have a reason for preferring eval to, say, a hash.



Henry Lenzi

unread,
Jul 27, 2014, 3:38:26 PM7/27/14
to Racket list
Thanks for your answers.

- Henry Lenzi

Henry Lenzi

unread,
Jul 27, 2014, 3:43:15 PM7/27/14
to Racket list
By the way, just out of curiosity, why do I need to nest EVALs.
E.g., this won't work (notwithstanding the namespace issue in the
definitions panel, just using the REPL):

> (map eval '(*med-name* line *quant-str* pl))
'(hctz25 "-----------" "30" "pills")

Why wasn't the symbol "hctz25" expanded? I'm even more confused,
because this works (again, in the REPL).

> (eval *med-name*)
"Hydroclorothiazide 25mg"

TIA,

Henry Lenzi

Neil Van Dyke

unread,
Jul 27, 2014, 4:18:24 PM7/27/14
to us...@racket-lang.org
Maybe there should be a periodic public service announcement about not
using "eval". This time I will communicate in FAQ format:

Q: How do I use eval?
A: Don't use eval.

Q: But don't so many academic books feature eval prominently, so doesn't
that mean I should use try to eval?
A: Those books use eval for pedagogic reasons, or because the author is
enamored of some theoretical appeal of eval, or because the author wants
to watch the world burn. Don't use eval.

Q: But, but, but, I am just starting to learn, and eval seems to do what
I need.
A: Eval is almost certainly not what you want. Learn how to use the
other basics effectively. Don't use eval.

Q: I now am very comfortable with the language, I am aware that I should
avoid eval in almost all cases, and I can tell you why eval is actually
the right thing in this highly unusual case.
A: Cool, that's why eval is there.

Neil V.

Vincent St-Amour

unread,
Jul 28, 2014, 2:23:34 PM7/28/14
to Neil Van Dyke, us...@racket-lang.org
Maybe this should be linked to from the `eval' docs?

http://blog.racket-lang.org/2011/10/on-eval-in-dynamic-languages-generally.html

Vincent


At Sun, 27 Jul 2014 16:16:52 -0400,

Henry Lenzi

unread,
Jul 28, 2014, 2:42:33 PM7/28/14
to Racket list


Em domingo, 27 de julho de 2014, Matthew Butterick <m...@mbtype.com> escreveu:
Because *med-name* is different. The other three are the names of variables that hold strings. But *med-name* is the name of a variable that holds the name of another variable that holds a 

Yes, always good to be reminded about how cons cells really work. 
I was wandering why eval just didn't follow the pointers to "expand" the symbol to the string. 

- Henry 

Henry Lenzi

unread,
Jul 28, 2014, 2:45:18 PM7/28/14
to Racket list
Hello again-  

I suppose this doesn't look like a case for eval when you first look into it, but since I would like to export the shorthand symbols to a file, I just might need eval. 

- Henry. 

Neil Van Dyke

unread,
Jul 28, 2014, 3:49:18 PM7/28/14
to Vincent St-Amour, us...@racket-lang.org
I don't know the current state of the "eval" docs in the manual, but I
think they should have a big warning at the very front, intended to
scare away newbies.

Remember that Racket is often used in conjunction with many different
Scheme-based and other Lisp-based textbooks and courses. It seems that
many CS instructors and textbook authors like to talk about ``EVAL'' (as
an abstract operation) when talking about some models of evaluation, and
"eval" (as an accessible language binding) to say, gosh, aren't dynamic
languages interesting and powerful. So, we can't blame every fourth
newbie for trying to use "eval" unnecessarily, in ways that make for bad
software engineering.

Given this reality of confusing instruction, I'm thinking that, as a
reactive measure, "#lang paddle" will disable "eval" by default.
Attempting to use "eval" will give you an error message, unless you have
an assertion form like
"(i-have-read-the-foo-document-and-understand-that-eval-is-usually-the-wrong-thing-but-honest-i-know-what-i-am-doing)".

Cheers,
Neil V.

Henry Lenzi

unread,
Jul 28, 2014, 4:23:39 PM7/28/14
to Racket list
Hi Neil --

So how do you export hash keys as symbols to a file that can be read
in again, not as string?

Now, I haven't gotten around to reading the whole of Racket Scheme's
documentation... Things are looking kind of hard.

What I'm attempting to do is then read back the symbols defined, such
as the one below:

(define hctz25 "Hydrochlorothiazide 25mg")

> (close-input-port in)
> (define in (open-input-file "Recipe.txt"))
> (string->symbol (read-line in))
'|'hctz25|

But what I really want is the "hctz25" symbol that evaluates to a
string. If I don't use string->symbol, I get the string "hctz25". And
why the bars ("|")? I've read

http://docs.racket-lang.org/reference/reader.html#%28part._parse-hashtable%29

but it didn't help me much.

Of course, the ultimate purpose would be to re-evaluate the imported
symbol and reconstruct a medical recipe. The purpose of these
baby-steps exercises is porting a medical recipe program I've written
originally in Forth that allowed me to service 5.000 patients creating
a little database of shorthand recipes that then expand into real
medical recipes. I got hundreds of patients on renewable recipes for,
say, hypertension. Hand writing is no fun. Typing them in Word is no
fun. The hospital has is its own software, but it's is a load of
baloney, extremely buggy, if you ask me, so I'm rolling my own again,
except I want to print directly on the model paper our service uses,
so I want graphics like Racket Scheme has (very good capabilities, as
far as my needs are concerned).

With Forth, it's very easy to design DSLs, because there's no syntax
and you get a lot of advanced features for free. For instance, there's
no need to write a parser for my little language. However, since Forth
implementations fall short of dealing with images, graphics (unless
you take the royal road to pain and learn to program for the Win32 API
and how it works for a particular Forth vendor), I'm looking at Racket
Scheme.

TIA,

Henry Lenzi

Vincent St-Amour

unread,
Jul 28, 2014, 5:04:55 PM7/28/14
to Henry Lenzi, Racket list
Henry,

It looks like modules may be what you're looking for.

You could have a file that defines a substance and exports it

;; a.rkt
#lang racket
(provide hctz25)
(define hctz25 "Hydrochlorothiazide 25mg")

and then a recipe file that imports the previous file

#lang racket
(require "a.rkt")
hctz25

The module system is the preferred way to share definitions across
multiple files in Racket.

Would that solve your problem?

Vincent


At Mon, 28 Jul 2014 17:21:40 -0300,

Alexander D. Knauth

unread,
Jul 28, 2014, 5:06:59 PM7/28/14
to Henry Lenzi, racket users list
On Jul 28, 2014, at 4:21 PM, Henry Lenzi <henry...@gmail.com> wrote:

Hi Neil --

So how do you export hash keys as symbols to a file that can be read
in again, not as string?

Now, I haven't gotten around to reading the whole of Racket Scheme's
documentation... Things are looking kind of hard.

What I'm attempting to do is then read back the symbols defined, such
as the one below:

(define hctz25 "Hydrochlorothiazide 25mg")

(close-input-port in)
(define in (open-input-file "Recipe.txt"))
(string->symbol (read-line in))
'|'hctz25|

But what I really want is the "hctz25" symbol that evaluates to a
string. If I don't use string->symbol, I get the string "hctz25". And
why the bars ("|”)?

As an explanation of the bars:
If you use read-line, does it return the string "hctz25", or the string "'hctz25" (with the quote as the first character)?
 > (string->symbol "hctz25")
 'hctz25
 > (string->symbol "'hctz25")
 '|'hctz25|

I think you’d want to use read for that though, not read-line.  

You might be able to use something a bit like this:
(define hash (make-hash))
(match (read in)
  [`(define ,sym ,str) (hash-set! hash sym str)])
(hash-ref hash 'hctz25)

Or something like this:
(define hash
  (for/hash ([def (in-port read in)])
    (match-define `(define ,sym ,str) def)
    (values sym str)))
(hash-ref hash 'hctz25)

Matthias Felleisen

unread,
Jul 28, 2014, 11:22:57 PM7/28/14
to Neil Van Dyke, us...@racket-lang.org

Neil, I think that would be a wonderful service that you could script as a little Racket daemon. It could broadcast this message every quarter or so (as an addendum to PLT Design Inc's financial statement) and the broadcast could take different shapes and forms and use different words (FAQ, TLL style, The Essayist style, etc). Wanna do it :-)

-- Matthias

Neil Van Dyke

unread,
Jul 28, 2014, 11:36:14 PM7/28/14
to Matthias Felleisen, us...@racket-lang.org
If we keep a human in the loop, we can see how users respond to the
different messages, and adapt our form of expression as necessary. If
all else fails, the nuclear option: viral YouTube video of "Don't use
eval" as interpretive dance.

Neil V.

Roman Klochkov

unread,
Jul 29, 2014, 12:00:51 AM7/29/14
to Henry Lenzi, racket users list
You may also export all hash to file and later read it.

http://docs.racket-lang.org/reference/serialization.html

(require racket/serialize)

(define my-hash (make-hash))

(define out (open-output-file "dump.dat"))
(write (serialize my-hash) out)
(close-output-port out)

... later
(define in (open-input-file "dump.dat"))
(define my-hash (deserialize (read in)))
(close-input-port in)

Mon, 28 Jul 2014 17:21:40 -0300 от Henry Lenzi <henry...@gmail.com>:
--
Roman Klochkov

Alexander D. Knauth

unread,
Jul 29, 2014, 12:17:17 AM7/29/14
to Henry Lenzi, racket users list
I don’t think you even need to serialize it for that:
(define my-hash (make-hash))
(define out (open-output-file “dump.dat”))
(write my-hash out)
(close-output-port out)

… later
(define in (open-input-file “dump.dat”))
(define my-hash (read in))
(close-input-port in)

Henry Lenzi

unread,
Jul 29, 2014, 10:56:17 PM7/29/14
to Racket list
Thanks, Vincent. But a recipe is more than those simple definitions.
Actually, it would be something like:


MEDICATION DOSE UNITS ----------------- QUANTITY FORM

INSTRUCTIONS FOR TAKING MEDICATION

In my previous Forth version, this was extremely easy to achieve, as
Forth is syntax-less, and "code is data, and data is code". So the
recipe turned out to be a mini language written in Forth itself.

These seems to be harder in Scheme... Some here seem to shun code/data
("don't use eval") in favor of what would amount ultimately to
string-based methods, as far as I understand it.

- Henry

Henry Lenzi

unread,
Jul 29, 2014, 11:45:33 PM7/29/14
to Racket list
(read in) doesn't work.

This should be simple...I write
> (define out (open-output-file "Recipe.txt"))
> (print *med-name* out)
> (close-output-port out)

and what I see in the file is:
'hctz25

How can I import this from a file?
If I use (read in), I get:

''hctz25

(two quotes)

The issue here was that there was a definition
(define hctz25 "Hydrochlorothiazide 25mg)

and hctz25 thus evaluates to a string.

How can I get it back from a file, retaining the capacity to evaluate
it to its definition. That's sort of the issue.

TIA
- Henry

Andrew Dudash

unread,
Jul 30, 2014, 10:42:46 AM7/30/14
to Henry Lenzi, Racket list
Thanks, Vincent. But a recipe is more than those simple definitions.
Actually, it would be something like:

MEDICATION DOSE UNITS ----------------- QUANTITY FORM
     INSTRUCTIONS FOR TAKING MEDICATION 

The module idea would still work. You can define your definitions in one file, provide them, and then require them in another file. The definitions can be as complex as you like.

In my previous Forth version, this was extremely easy to achieve, as
Forth is syntax-less, and "code is data, and data is code". So the
recipe turned out to be a mini language written in Forth itself.

There doesn't seem to be any need for "code as data, data as code" here. Instead of mapping abbreviations to full names with identifiers and values, why not use keys and values with a hash-table? It removes the need for 'eval'.

  (define meds (hash 'hctz "Hydrochlorothiazide"
                              'cough-drops "Cough Drops"))

  (define (abbreviation->full-name abbreviation)
    (dict-ref meds abbreviation))

If the mapping is constant, you can store it in another module, provide, and require it, like Vincent explains. If your mapping is updated over time, you can save it to a file as Roman explains. Saving it to a file doesn't require text parsing. With print, read, and serialize, all the hard work is already taken care of.


Alexander D. Knauth

unread,
Jul 30, 2014, 11:34:40 AM7/30/14
to Henry Lenzi, racket users list
On Jul 29, 2014, at 11:42 PM, Henry Lenzi <henry...@gmail.com> wrote:

(read in) doesn't work.

This should be simple...I write
(define out (open-output-file "Recipe.txt"))
(print *med-name* out)
What you probably want here is write, not print.
(close-output-port out)
Print is good for printing values like they could be written in a program, but it is not the opposite of read.
Write is the opposite of read.  
In general, read usually puts an extra single quote in front of everything.  
If you use print, then it will keep the quote, but if you use write then it will drop it.  


and what I see in the file is:
'hctz25

How can I import this from a file?
If I use (read in), I get:

''hctz25

(two quotes)

If the file contains this (no quotes in front of it): hctz25
Then using read-line on the file port will produce a string: "hctz25"
and using read on the port will produce a quoted symbol: 'hctz25
If the file contains this (with a quote in front of it): 'hctz25
Then using read-line on the file port will produce a string: "'hctz25"
and using read on the port will produce this (with two single quotes): ''hctz25
This: 'hctz25 is equivalent to this: (quote hctz25) and so
this: ''hctz25 is equivalent to this: '(quote hctz25) which is equivalent to (list 'quote 'hctz25)

If you do this: (write '(define hctz25 "Hydrochlorothiazide 25mg") out), then the file will have this:
(define hctz25 "Hydrochlorothiazide 25mg")
And  then if you use read on the file port, you get this back:  '(define hctz25 "Hydrochlorothiazide 25mg")

Daniel Prager

unread,
Jul 30, 2014, 5:33:43 PM7/30/14
to Henry Lenzi, Racket Users
Hi Henry

Racket is very suitable for writing DSLs, or even whole Ls (more advanced!). As you'd expect, the idioms for DSL construction in straight Racket are different from those in Forth and will take a bit of familiarization and adjustment.

Would you be willing to share a more fully-fledged example of a shorthand medical recipe (input) and reconstructed recipe (output) so that the Racket Community can better understand what sounds like a very worthwhile project?


Dan

Henry Lenzi

unread,
Jul 30, 2014, 8:52:00 PM7/30/14
to Daniel Prager, Racket Users
Hi Daniel --

Do you mean the Forth files?
I don't belienve they would make much sense to you, but it would go
something like this (as you can see, that is a FORTH definition):

: NAME S"John Doe"
CU4
HCTZ25 30P 1CPM
OMZ20 30P 1CPM INSTOMZ
SIMVA20 30P 1CPN
L\D ;

Expands to (NOTE: Some things are germane to our public health
system, such as renewing "continuous use" gratis medications, recipe
valid for 4 months):

John Doe

Continuous use - 4 months

Hydrochlorothiazide 25mg ---------------- 30 pills

Take 1 pill P.O. in the morning.

Omeprazol 20mg ----------------------------- 30 pills

Take 1 pill P.O. in the morning, 1/2 hour
before breakfast.

Simvastatin 20mg ---------------------------- 30 pills

Take 1 pill P.O. at night.

City, xx/xx/xxxx


So what´s happening here is that inside the FORTH definition,
everything delimited by ":" and ";" is a FORTH word, as they say, that
is to say, valid FORTH code.
The very cheap trick here is simply writing a file with plain text
(but called .fth, .f or other FORTH designations for filetypes)
begining with a ":", ending with a ";", and everything in between,
which are the FORTH words.
The FORTH reader than opens this file. As soon as it hits the ":", it
recognizes it's FORTH code. It's all amazingly stupid. However, what
you get is: a DSL hassle-free (no parsing/lexing), a flat-file
database for free (the name of the files), an interpreter (comes with
the territory). And code is data, data is code, in a very, very
concrete way.


Cheers,

Henry Lenzi

____________________

Robby Findler

unread,
Jul 30, 2014, 9:04:06 PM7/30/14
to Henry Lenzi, Racket Users
Hi Henry: do you work in the heath system? If you have any pointers
I'd be interested to read about your work and how you use things like
Forth (or maybe someday, Racket! :) in that work.

Best,
Robby

Henry Lenzi

unread,
Jul 30, 2014, 9:44:28 PM7/30/14
to Robby Findler, Racket list
Yes, I do, as physician.

This is all internal, nothing is or will be published (but I wouldn't
care/mind releasing the code, when and if I have it). The way to think
of this is: I could be typing stuff out on Word, or I could use the
hospital's buggy and horrible software. But I'll just roll my own,
like I did last year on another job (the FORTH thing - which is
abandoware right now, although it served me well).

This is isn't complex software, you know? This is very stupid stuff.
(But I do realize people make money selling stupid software for
physicians...). What I think I can achieve with Scheme is printing
directly on a .jpeg image (the hospital's layout form for recipes),
using Racket's imaging library. This would be...fun! AND useful. In a
more advanced stage, I can play with optimization and constraints
(e.g., calculating how to properly fit stuff on the page, etc.)

Another thing I want to write is software to monitor our 300
diabetic/hypertensive patients. I had some great ideas looking at
Scheme's graphic capabilities. This would be something
spreadsheet-like, with various (graphical) bells and whistles for
alerts (such as renal function parameters, global cardiovascular risk,
etc.)

We're not a a big hospital complex in the USA. We're in a big public
health hospital complex in southern Brazil. Our hospital doesn't have
the cash for the latest and greatest for medical software. However, I
still prefer my shorthand DSL than anything else I've seen. You show
"HCTZ25 30P 1XD or OMZ20 30P 1P/M" to *any* doctor and I'm willing to
bet they'll IMMEDIATELY grok what it means. That's the power of a
proper DSL.

And, when and if I write this thing, it'll be for me and my colleague
only (that's 3.000 patients), possibly extending to the rest of the
team (that would be 9.000 patients). So, internal, in-house.

Who knows when I'll have this. I'm a busy physician (like all of us).
If I have to start reading advanced mumbo-jumbo or papers with
denotational semantics in order to understand what in the world is the
matter with EVAL in Racket Scheme, I might just give up and go back to
Win32 API (easier, right?) and my proprietary/licensed FORTH that can
ship executables (royalty-free).

(I'm wasting too much time here, when I should be testing the answers
the fine Racketeers have provided me with) ;-)

Cheers,

Henry Lenzi

Cheers,
Henry Lenzi


Cheers,

Henry Lenzi

Daniel Prager

unread,
Jul 30, 2014, 9:50:05 PM7/30/14
to Henry Lenzi, Racket Users
Thanks Henry

That's exactly what I was interested in. I'm at work at the moment (Australia), but will have a bit more of a look later tonight

But I have an interest in the health sector, and would be interested in contributing to a public domain project, especially if we can make something neat / quick. I imagine others may be interested too.

The reason I asked to see the big picture is that often in software development a bit more context helps. E.g. Maybe parts of your existing database can be sucked in and re-purposed.

Dan


--
Daniel Prager
Agile/Lean Coaching, Software Development and Leadership
Twitter: @agilejitsu 

Henry Lenzi

unread,
Jul 30, 2014, 9:52:44 PM7/30/14
to Daniel Prager, Racket list
Hi Dan --

What you saw was precisely the database file (it's a file written in
the programming language FORTH).

Cheers,
Henry

On Wed, Jul 30, 2014 at 10:48 PM, Daniel Prager

____________________

Henry Lenzi

unread,
Jul 30, 2014, 9:59:37 PM7/30/14
to Vincent St-Amour, Racket list
Actually, this is interesting.

This might lead to having hundreds of definition files, however (say,
one for each medication defintion).

I would have to look into how I can save a module to a file (Alexander
Knauth explained that (write '(define hctz25 "Hydrochlorothiazide
25mg") out) would write the correct definition to a file.

So, a recipe might be just a module. The symbols would be correctly
imported (and "interned", I suppose you guys say...?) in the run-time.

Thanks, Vincent.

Cheers,
Henry

On Mon, Jul 28, 2014 at 6:03 PM, Vincent St-Amour <stam...@ccs.neu.edu> wrote:

Henry Lenzi

unread,
Jul 30, 2014, 10:07:38 PM7/30/14
to Vincent St-Amour, Racket list
Actually, it occurred to me that re-assembling the symbols in the
recipe/module might involve macrology, in order to put in the
following format:

MEDICATION QUANTITY LINE NUMBER FORM
INSTRUCTIONS

(that's like OMZ20 30CP INSTOMZ that I exemplified in another message,
expanding to:

Omeprazol 20mg ----------------------- 30 pills
Take 1 P.O. etc.)

So...bad! Or worse, parsers etc Which would take me a whole lot of
time (Dragon book? R U kidding me?! ;-))

Cheers,
Henry Lenzi

Henry Lenzi

unread,
Jul 30, 2014, 10:52:51 PM7/30/14
to Vincent St-Amour, Racket list
How do you tell Racket Scheme to save a module (programatically, that
is)? I only see syntax for importing modules in the documentation.

Is that even possible?

TIA,
Henry

On Mon, Jul 28, 2014 at 6:03 PM, Vincent St-Amour <stam...@ccs.neu.edu> wrote:

Galler

unread,
Jul 31, 2014, 12:03:53 AM7/31/14
to us...@racket-lang.org
Henri
Is this what you're after?



#lang racket/base

(require (for-syntax syntax/parse
racket/base
))


(provide make-script)

(begin-for-syntax

(define-syntax-class unit-dictionary
#:attributes (str)
(pattern (~literal p)
#:with str "pills")
(pattern (~literal c)
#:with str "capsules"))

(define qu-regex (pregexp "^(?i:(\\d+)([^\\d]{1}))$"))

(define-syntax-class quantity-units
#:attributes (str)
(pattern candidate:id
#:with (_ q:id u:unit-dictionary) #`#,(map (compose
string->symbol string-downcase) (or (regexp-match qu-regex (symbol->string
(syntax->datum #'candidate)))
null))
#:with str #`#,(apply format "~a ~a" (syntax->datum #'(q u.str)))))


(define-syntax-class formula-dictionary
#:attributes (str)
(pattern (~literal hctz)
#:with str "Hydrochlorothiazide")
(pattern (~literal omz)
#:with str "Omeprazol")
(pattern (~literal simva)
#:with str "Simvastatin"))


(define formula-regex (pregexp "^(?i:([^\\d]+)(\\d+))$"))

(define-syntax-class formula
#:attributes (str)
(pattern candidate:id
#:with (_ code:formula-dictionary packaging:id) #`#,(map (compose
string->symbol string-downcase) (or (regexp-match formula-regex
(symbol->string (syntax->datum #'candidate)))

null))
#:with str #`#,(apply format "~a - ~a mg" (syntax->datum
#'(code.str packaging)))))


(define-syntax-class medication
#:attributes (str)
(pattern (f:formula q-u:quantity-units)
#:with str #`#,(apply format "~a ---------------------~a\n"
(syntax->datum #'(f.str q-u.str)))))



(define-syntax-class periodicity-dictionary
#:attributes (str)
(pattern (~literal cu)
#:with str "Continuous use")
(pattern (~literal iu)
#:with str "Intermittent use"))


(define duration-regex (pregexp "^(?i:(cu|iu)(\\d+))$"))

(define-syntax-class duration
#:attributes (str)
(pattern candidate:id
#:with (_ code:periodicity-dictionary length:id) #`#,(map
(compose string->symbol string-downcase) (or (regexp-match duration-regex
(symbol->string (syntax->datum #'candidate)))

null))
#:with str #`#,(apply format "~a - ~a months" (syntax->datum
#'(code.str length)))))


(define-splicing-syntax-class sentence
#:description "sentence"
#:attributes (ast)
(pattern (~seq patient-name:str d:duration meds:medication ...)
#:with ast #'((patient . patient-name) (directions . d.str)
(medication . meds.str) ...)))


)

(define-syntax (make-script stx)
(syntax-parse stx
((_ x:sentence) #''x.ast)
(_ #'#f)))


(make-script "John Doe" CU4 (HCTZ25 30P) (OMZ20 30P) (SIMVA20 30c))
(make-script "Jane Doe" IU6 (OMZ100 55C))

#|
program output
'((patient . "John Doe")
(directions . "Continuous use - 4 months")
(medication . "Hydrochlorothiazide - 25 mg ---------------------30 pills\n")
(medication . "Omeprazol - 20 mg ---------------------30 pills\n")
(medication . "Simvastatin - 20 mg ---------------------30 capsules\n"))
'((patient . "Jane Doe") (directions . "Intermittent use - 6 months")
(medication . "Omeprazol - 100 mg ---------------------55 capsules\n"))

|#

Daniel Prager

unread,
Jul 31, 2014, 9:51:00 AM7/31/14
to Henry Lenzi, Racket Users
Hi Henry

I'm taking a similar approach to Galler for a proof-of-concept, but without the macrology. This should make the ideas more widely accessible (and my skill with macros is limited).

First, thank-you again for supplying the example. By comparing input and output readers can infer the kinds of things your DSL does, even with only a smattering of Forth.

The first thing to do is to devise a more Lispy representation of the DSL. Let's take the original:

: NAME S"John Doe"
   CU4
   HCTZ25 30P 1CPM
   OMZ20 30P 1CPM INSTOMZ
   SIMVA20 30P 1CPN
   L/D;

and re-cast it using parentheses and prefix notation. I've chosen to notate as follows, adapting from Galler:

'(script
  (name "John Doe")
  (directions (CU 4))
  (medication (HCTZ 25) (P 30) (CPM 1))
  (medication (OMZ 20) (P 30) (CPM 1) (INSTOMZ))
  (medication (SIMVA 20) (P 30) (CPN 1)))

[I've left off the L/D because I didn't follow the mapping, but you get the idea.]

Now -- in practice -- a physician doesn't want to fiddle with parentheses, so a simple parser (16 lines in the proof-of-concept) is needed to go from something close to the original DSL to the new, parenthesized DSL.

From this new DSL there are many ways to get to the expanded script. Because it keeps coming up (and it's a quick hack ;-) I've used eval. A simple desugaring approach (as described in Shriram's PLAI book and course) would also work well, IMO.

Here's my proof-of-concept in action...

Input:
(shorthand->script
"John Doe
CU4
HCTZ25 30P 1CPM
OMZ20 30P 1CPM INSTOMZ
SIMVA20 30P 1CPN")

Output:
John Doe

Continuous use - 4 months

Hydrochlorothiazide 25mg ---------------- 30 pills

    Take 1 pill in the morning.

Omeprazol 20mg ---------------- 30 pills

    Take 1 pill in the morning, 1/2 hour before breakfast.

Simvastatin 20mg ---------------- 30 pills

    Take 1 pill at night.


To summarize:
  1. Design the Lispy version of the DSL
  2. Parse from the input DSL to the Lispy DSL
  3. Expand from the Lispy DSL to the full script
  4. Bells and whistles: graphics, file-handling, proper user-interface, error-handling, etc.
I hope that helps.

I think this would be a good open-source project, and well-suited to Racket. 

BTW: If you want to produce nicely type-set output, consider looking into the Scribble language / tool.

Dan

Matthias Felleisen

unread,
Jul 31, 2014, 10:56:42 AM7/31/14
to Henry Lenzi, Racket list

On Jul 30, 2014, at 9:57 PM, Henry Lenzi <henry...@gmail.com> wrote:

> This might lead to having hundreds of definition files, however (say,
> one for each medication defintion).


Use sub-modules and load them:

#lang racket

(module prescription1 PPL ...)

(module prescription2 PPL ...)

etc.

Your PPL (prescription programming language) may define a standard interface that provides just the right pieces in a standard way, like a Scribble file provides a document, and that your rendering run-time turns the prescriptions into the desired JPEG shape. If your hospital ever moves to TIFF or WHATEVER format, you can shift the latter easily.

Doing so will reduce the time you have to spend away from patients and with the software. That's what we're trying to help you with, by looking ahead just a bit

And if you can formulate specs, I am sure people on this list will contribute. It's the Racket way.

-- Matthias

Vincent St-Amour

unread,
Jul 31, 2014, 2:20:59 PM7/31/14
to Henry Lenzi, Racket list
At Wed, 30 Jul 2014 22:57:59 -0300,
Henry Lenzi wrote:
> This might lead to having hundreds of definition files, however (say,
> one for each medication defintion).

If you want. You can have as many definitions per file as you'd like,
though, so you don't have to.

When you import a module, all its exports (variables that are
`provide`d) can be used in the importing module.

> I would have to look into how I can save a module to a file (Alexander
> Knauth explained that (write '(define hctz25 "Hydrochlorothiazide
> 25mg") out) would write the correct definition to a file.

Any file that starts with a #lang line (such as "#lang racket") defines
a module, which you can require using `(require "filename.rkt")`.

Are you trying to generate these definitions programmatically? I was
under the impression that you'd write them by hand, in which case you
just have to edit the file.

Vincent

Henry Lenzi

unread,
Aug 1, 2014, 11:46:05 PM8/1/14
to Racket list
Hello everyone - 

First of all, a big Thank You to all of you and for taking the time for responding. 

I'll have to set aside sometime during this weekend to see if I can understand the ideas you've been so kind to offer. 

However, I should confess that I've made some progress with way simpler stuff which I hope to post later on.  Like I've said, this is stupid software. Anyways, none of this is final.

It really just used a plain text solution, since the format if a recipe is so rigid. The question of expanding the symbols from files to run-time was easier than I thought. 

The idea of using modules might have the nice collateral effect if some sort of primitive type (or syntax) checking for free. I like the idea someone offered of using modules for medication definitions. Actually, one module per definition makes it very easy for future users to add new medications. The ease of syntax is important because it allows for the customization by non-sophisticated users (physicians, nurses). 

Cheers,
Henry Lenzi. 

Henry Lenzi

unread,
Aug 3, 2014, 3:32:09 PM8/3/14
to Racket list
; Hello all --
; So here's how I solve all those little problems regarding symbols
and evaluation of medication definitions.
; Would you please bear with me? I apologize for the length.
; This is the approach I've taken. I've chosen no to use any macrology
or parser/lexer technique because I don't grok them and they
; don't really seem necessary, for reasons explained in the code comments.
; I have not decided to hash tables, for the following reason: there's
a part of the code (the drug definitions, the instructions), that
; should be easy enough for non-programmers to edit. If they are kept
very simple, it's possible, because the users have to edit those
; files. So, even though it is source code, it's not as intimidating
as editing source code if hash tables.
; Another aspect is that I hope modules provided some sort of safety
in terms of syntax checking. That is to say, if you used make a
; typo in the medication part of the DSL, the system will (hopefully)
bork because no such module exists. I believe this also creates
; an opportunity for "syntax validation" if a proper input phase is
designed. But Lisp/Scheme being a dynamic language, the run-time
; will bork immediately once it sees funny things. This is a way to
guarantee the DSL is correct, which we get for free by using Racket.
; A fourth aspect is that, if each drug is kept a different module
(which I haven't done here, BTW), then we can make for easier
; internationalization, by keeping modules by languages, e.g.,
hctz25-en, hctz25-pt_br. I believe Dan has an interest in this project
too,
; so it's best to design with that in mind.
; Final comment regards "database". We get "database" for free, by
registering prescriptions with patient register numbers. The OS
; takes care of pretty musch anything else. And there's no need for
atomicity and concurrency. Like I said, this is stupid code.
;
;
#lang racket

; code-review-for-racketeers-2014-08-03-a.rkt
;
; For this exercise, suppose a Recipe.txt file. Let´s suppose the idea
is that the physician
; has two options: 1) he or she opens Notepad and writes the
prescription file (Recipe.text);
; 2) or, the software asks for inputs and writes the file (this will
not be covered in this
; exercise). The written prescription in the shorthand DSL would look
like below, with the
; exception of a first field with patient ID data not included (to be
done later).
; The prescription has a rigid syntax would look like this (line
breaks included):
; 1-
; hctz25 30 pl 1xd
;
; 2-
; simva20 30 pl 1xn


; Needed for EVAL, used later on
(define-namespace-anchor a)

; These definitions should be in a different module.
; This way we get syntax checking for free.
; MED - medication. Includes dosage.


(define hctz25 "Hydrochlorothiazide 25mg")

(define simva20 "Simvastatin 20mg")
; FORM - whether the patient will take home pills, a tube, a flask, capsules
(define pl "pills")
; POS - posology, whether the patient will take 1 pill 3x a day, or 2
pills 2x a day, etc.
(define 1xd "Take 1 pill P.O. 1x/day")
(define 1xn "Take 1 pill P.O. 1x at night")
; INSTs - special instructions. INST is just a prefix INST+MED without
the dosage.
(define INSTOMZ "half an hour before breakfast, with a glass of water")
; Formatters - simple for now, but should be a function of the space available.
(define line "-----------")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The main part of a prescription DSL is pretty rigid in syntax, being
composed of blocks of theses parts:
; MEDICATION QUANTITY FORM POSOLOGY INSTRUCTION, or MED QUANT FORM POS INST.
; Please note that, in this DSL, the MED part includes the drug dosage
(e.g., HCTZ25, where
; the HCTZ designates the drug, and the 25 the dosage).
; An example would be:
; HCTZ25 30 PL 1XD
; meaning: Hydrochlorothiazide 25mg -------------- 30 pills
; Take 1 pill P.O. 1X day
; INST are special instructions. They basically are more detailed
explanation to the patient about
; how to use the medication properly. Not always there's a INST in the
prescription DSL.
; INSTs are, in fact, a PREFIX for the MED without the dose. For
example, OMZ20 is Omeprazol 20mg.
; The instruction for OMZ would be INSTOMZ ("half an hour before
breakfast, with a glass of water").
; In this case, the DSL line would be:
; OMZ20 30 PL 1XD INSTOMZ
; meaning: Omeprazol 20mg ------------------- 30 pills
; Take 1 pill P.O. 1X day
; half an hour before breakfast, with
; a glass of water
; Questions regarding proper formatting of INST are not addressed at
this moment.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Now follows a description of some problems I encountered and the
choices made in solving them:
; (define in (open-input-file "Recipe.txt"))
; If you just (string-split (read-line in)) you'll get:
; => '("hctz25" "30" "cp" "1xd")
; and that will not evaluate the symbols to their string descritptions.
; Because of that, you need to do a:
; > (map string->symbol (string-split (read-line in)))
; which will evaluate to
; => '(hctz25 |30| cp 1xd)
; This would be ideal to MAP EVAL to, but the problem is the |30|
; So, the idea is SET!ing that list to a name we can call easily, i.e.,
; med-line-holder, because then we can extract the pieces (since we
can't do list
; surgery easily, such a "replace the the element at position 1 with
so-and-so element").
; Since the prescription syntax is pretty rigid, we can get away with this
; simple approach.

(define med-line-holder '()) ; initial value of med-line-holder is an empty list
(define med-name-holder '())
(define med-quant-holder '())
(define med-form-holder '())
(define med-pos-holder '())
(define med-inst-holder '()) ; remember, not always INSTructions
happen in a DSL prescription .

(define in (open-input-file "Recipe.txt"))

(port-count-lines! in)
(define (clpr) (close-input-port in))

; a med-line-holder is a list that has MED QUANT FORM POS (and sometimes INST)
; This is obtained from a plain text file. When it is read, it becomes something
; like this: '(hctz25 |30| cp 1xd)
(define (set-med-line-holder)
(set! med-line-holder (map string->symbol (string-split (read-line in)))))

(define (set-med-name-holder)
; (set! med-name-holder (eval (car med-line-holder))) ;; in the REPL
(set! med-name-holder (eval (car med-line-holder)
(namespace-anchor->namespace a))))

(define (set-med-quant-holder) ; the CADR of the med-line-holder
; (set! med-quant-holder (eval (symbol->string (cadr med-line-holder))))
(set! med-quant-holder (eval (symbol->string (cadr med-line-holder))
(namespace-anchor->namespace a))))

(define (set-med-form-holder) ; the CADDR of the med-line-holder -
gets the FORM, e.g., pills, etc.
; (set! med-form-holder (eval (symbol->string (caddr med-line-holder))))
(set! med-form-holder (eval (caddr med-line-holder)
(namespace-anchor->namespace a))))

(define (set-med-pos-holder) ; the CADDDR of the med-line-holder -
gets the POS, e.g., 1xd
; (set! med-pos-holder (eval (symbol->string (cadddr med-line-holder))))
(set! med-pos-holder (eval (cadddr med-line-holder)
(namespace-anchor->namespace a))))


(define (set-med-inst-holder) ; the LAST of the med-line-holder - gets the INST
; (set! med-pos-holder (eval (symbol->string (last med-line-holder))))
(set! med-pos-holder (eval (last med-line-holder)
(namespace-anchor->namespace a))))

; One problem here regards the optional INST instructions.
; How to create a SETter function that will only SET! med-inst-holder
; if there's an INST instruction? Note that INST is a prefix. A real
instruction is, e.g.,
; INSTOMZ (for OMZ20).
(define (look-for-line)
(if (regexp-match #px"\\d\\-" (read-line in))
(begin
(set-med-line-holder)
(set-med-name-holder)
(set-med-quant-holder)
(set-med-form-holder)
(set-med-pos-holder))
'NO-LINE))

(define (display-stuff)
(newline)
(display med-line-holder) (newline)
(display med-name-holder) (newline)
(display med-quant-holder) (newline)
(display med-form-holder) (newline)
(display med-pos-holder) (newline))
; The problem remains of what to do with the eventual INST.


; Successive calls to (look-for-line) would read the next lines.
; Output would alternate between a DSL line, or a NO-LINE (from look-for-line,
; if it hits a line with no text in Recipe.txt
(look-for-line)
;(display-stuff)


(define (output-a-line)
(string-join (list med-name-holder line med-quant-holder med-form-holder "\n"
med-pos-holder "\n")))

(define (format-a-line)
(display (output-a-line)))

;(define (output-a-line)
; (display (string-join (list med-name-holder line med-quant-holder
med-form-holder "\n"
; med-pos-holder "\n"))))
(newline)
;(output-a-line)

(format-a-line)

; PROBLEMS
; 1) How do we find out how many lines to (look-for-line)?
; This is one of the resons I specified the "1-", "2-" in the Recipe.txt. Not
; only it makes for easy visual understanding, but it may be used
to provide a hint
; for this problem.
; Possible approaches:
; - Maybe this can be solved with REGEXPS? This information could
provide a sentinel
; variable for an iterator function?
; - Is there some sort if line counting function? (Note that I have set
; (port-count-lines! in) somewhere above in the code.
; 2) How do we know we've reached the end of the file?
; 3) How to deal with the not-always-present INST?
; - How do we check for INSTs? With a REGEXP?
; - Choosing between INSTs with REGEXPS is not necessary, as they
will be loaded in a module,
; so the system will "know" which one to choose.
; 4) Another idea would be "slurp" the whole of the prescription, and
then deal with evaluation. How?
; (define f1
; (file->string
; "C:\\Path\\to\\sources\\Recipe.txt"))
;> (string-normalize-spaces f1)
;"1- hctz25 30 pl 1xd 2- simva20 30 pl 1xn"
;
; That's all for now, folks!
; Many thanks for all the help so far, Racketeers!
; Cheers,
; Henry Lenzi

____________________

Henry Lenzi

unread,
Aug 3, 2014, 3:32:11 PM8/3/14
to Racket list
Uh oh, the GOOG botched formatting. Sorry about that!

Henry Lenzi

unread,
Aug 3, 2014, 3:42:15 PM8/3/14
to Racket list
It's best if I use pasteracket ("Hank's medication thingy")

http://pasterack.org/pastes/14535

-- Henry Lenzi

Alexander D. Knauth

unread,
Aug 3, 2014, 4:30:54 PM8/3/14
to Henry Lenzi, racket users list
What you want here is something like this:
;; Instead of (map string->symbol (string-split (read-line in)))
(for/list ([thing (in-port read in)]) thing)
;; and then you can do (map eval …) to that if you want.
;; Or you could do both at once like this:
(for/list ([thing (in-port read in)])
(eval thing namespace))

Henry Lenzi

unread,
Aug 3, 2014, 4:39:55 PM8/3/14
to racket users list
Alexander --

Thanks. But what would "thing" be?

Alexander D. Knauth

unread,
Aug 3, 2014, 4:42:22 PM8/3/14
to Henry Lenzi, racket users list
Actually come to think of it you can do this:
(sequence->list in)
Or this:
(port->list read in)

> ;; and then you can do (map eval …) to that if you want.
> ;; Or you could do both at once like this:
> (for/list ([thing (in-port read in)])
> (eval thing namespace))

Or for that:
(port->list (compose1 eval read) in)

>
>> ; So, the idea is SET!ing that list to a name we can call easily, i.e.,
>> ; med-line-holder, because then we can extract the pieces (since we
>> can't do list
>> ; surgery easily, such a "replace the the element at position 1 with
>> so-and-so element”).

look at list-set from unstable/list

Henry Lenzi

unread,
Aug 3, 2014, 7:59:55 PM8/3/14
to racket users list
Alexander's idea is interesting, but it onlt works if the
prescription file is not numbered (which is actually more natural),
such as if it were:
hctz25 30 pl 1xd
simva20 30 pl 1xn

> (define in2 (open-input-file "Recipe3.txt"))
> (port->list (compose1 eval read) in2)
'("Hydrochlorothiazide 25mg"
30
"cps"


"Take 1 pill P.O. 1x/day"

"Simvastatin 20mg"
30
"cps"


"Take 1 pill P.O. 1x at night")

The issue would then be about extracting and joining 4 or 5 (if it has
an INST instruction) items from that list.
string-join, however, will bork at numbers. So it's kind of the same
issue as previously than with |30|.

in what regards the presence of INSTs, maybe this could be approached
by first scanning the list for an INST instruction using REGEXPs, but
I don't know how to do that yet.


Thanks,

Henry Lenzi

On Sun, Aug 3, 2014 at 5:40 PM, Alexander D. Knauth

Alexander D. Knauth

unread,
Aug 3, 2014, 8:39:25 PM8/3/14
to Henry Lenzi, racket users list

On Aug 3, 2014, at 7:58 PM, Henry Lenzi <henry...@gmail.com> wrote:

> Alexander's idea is interesting, but it onlt works if the
> prescription file is not numbered (which is actually more natural),
> such as if it were:
> hctz25 30 pl 1xd
> simva20 30 pl 1xn
>
>> (define in2 (open-input-file "Recipe3.txt"))
>> (port->list (compose1 eval read) in2)
> '("Hydrochlorothiazide 25mg"
> 30
> "cps"
> "Take 1 pill P.O. 1x/day"
> "Simvastatin 20mg"
> 30
> "cps"
> "Take 1 pill P.O. 1x at night")
>
> The issue would then be about extracting and joining 4 or 5 (if it has
> an INST instruction) items from that list.
> string-join, however, will bork at numbers. So it's kind of the same
> issue as previously than with |30|.

Then just do this: (string-join (map ~a (port->list (compose1 eval read) in2)) instead.

Henry Lenzi

unread,
Aug 3, 2014, 11:08:39 PM8/3/14
to racket users list
Oh, OK. :-)

-- Henry

On Sun, Aug 3, 2014 at 9:38 PM, Alexander D. Knauth

Neil Van Dyke

unread,
Aug 3, 2014, 11:21:31 PM8/3/14
to Henry Lenzi, racket users list
I can see how someone might want to do tricks like this, to use the REPL
as user interface, for tinkering, and that could be very interesting or
clever.

However, just to be clear to students and professionals who might
stumble upon this thread... If I were actually doing this in production
for pharmaceutical prescriptions/labeling/instructions, then I would be
concerned about both program correctness and reducing potential for
operator error to cause failures. If we were starting with those as key
requirements for production use, then I think some of this technical
discussion might be irrelevant to that, since the software might be
implemented in a very different way.

Neil V.

Henry Lenzi

unread,
Aug 3, 2014, 11:54:28 PM8/3/14
to racket users list
Hello Neil -

First of all, I am not attempting tricks. I am doing the best I can,
the way I know how to (I will take the "clever" part as a compliment,
however). I have a few rational requirements, which I have explained.
Foremost among them is code simplicity. I saw no need so far for
parsers or macrology - I have justified this on the basis of the DSL.
As I had not been clear WRT the DSL before, I might have induced
people to make an option for macros. Also, I see a need for a part of
the program source-code to be easily customizable by users (such as,
for example, a Swedish user being able to add his/her own definitions
in simple module files, instead of tinkering with hash tables).

What I'm sensing is that you seem to be concerned about bugs with
Racket Scheme's EVAL. Is that it?
I do not understand what the problem with EVAL is. Would you please
state clearly what the problems are? I am a reasonably sophisticated
reader. You can even point to papers. I might not read them now, but I
even have books on stuff like denotational semantics (what I don't
have is much time, sadly).

Are you concered about using imperative style just on principle or
have you detected a specific issue?

Doesn't the fact that definitions are provided by modules reduce
potential bugs? As I understand it, if I type, e.g., "hctz30" instead
of "hctz25" the run-time environment will bork, as that would not be a
symbol in the read table. Correct?

Doesn't the DSL's rigid syntax reduce potential for bugs? Do you
suggest a formal parser? If so, can you explain the case why a formal
grammar would be a necessity? This is not a grammar/DSL that requires
recursion (in the Chomskyan sense). I don't see the point. Perhaps I'm
wrong. I would feel grateful if you cared to expand on that issue (if
that is an issue).

If there are too many bugs, can you cite one, two or maybe three that
would be of concern?

TIA,
Henry Lenzi
PS: I hope you realize that writing prescriptions by hand is a sure
way to get even more "bugs"...

Henry Lenzi

unread,
Aug 4, 2014, 12:11:46 AM8/4/14
to racket users list
I would just like to add that this is only something very embrionary.
There are a myriad ways to validate the user syntax when he/she
provides input.

We're just not there yet! ;-)

Cheers,
-- Henry

Alexander D. Knauth

unread,
Aug 4, 2014, 12:25:31 AM8/4/14
to Henry Lenzi, racket users list
Would this work for what you want?

If med.rkt contains this:
#lang racket

(provide (all-defined-out)
         #%datum #%top
         (rename-out [new-module-begin #%module-begin]))

(define-syntax-rule
  (new-module-begin med-thing ...)
  (#%module-begin (display (~a med-thing ... #:separator " "))))

(define hctz25 "Hydrochlorothiazide 25mg")
(define simva20 "Simvastatin 20mg")
(define pl "pills")
(define 1xd "Take 1 pill P.O. 1x/day")
(define 1xn "Take 1 pill P.O. 1x at night")
(define INSTOMZ "half an hour before breakfast, with a glass of water")
(define line "-----------")

And try-it.rkt contains this:
#lang s-exp "med.rkt"
hctz25 30 pl 1xd
simva20 30 pl 1xn

Then running try-it.rkt will produce the output:
Hydrochlorothiazide 25mg 30 pills Take 1 pill P.O. 1x/day Simvastatin 20mg 30 pills Take 1 pill P.O. 1x at night

Or if new-module-begin is defined like this instead:
(define-syntax-rule
  (new-module-begin med-thing ...)
  (#%module-begin (provide data) (define data (~a med-thing ... #:separator " "))))

Then doing (require “try-it.rkt”) will import data as the string "Hydrochlorothiazide 25mg 30 pills Take 1 pill P.O. 1x/day Simvastatin 20mg 30 pills Take 1 pill P.O. 1x at night".



Henry Lenzi

unread,
Aug 4, 2014, 1:24:40 AM8/4/14
to Alexander D. Knauth, racket users list
Hello Alex --

This is nice, the problem is separating the output into the proper
formatting. I feel this has to be done a step before the expansion
into the string form.
One thing I'm considering is that that the DSL is made of MED QUANT
FORM POS or MED QUANT FOR POS INST, so 4 or 5 items.
If we have a symbol list (before string expansion), than we can treat
INST as the divider marker. Otherwise, there's a linebreak at every
fourth item.

I'm looking into how to to this using a position function:
(define (position item list)
(- (length list)
(length (member item list))))

Knowing where the INST instructions occur help up decided whether we
can break a line into the
MED QUANT FORM
POS


or
MED QUANT FORM
POS
INST

forms (see the code snippet on http://pasterack.org/pastes/14535 )


Cheers,

Henry

____________________

Neil Van Dyke

unread,
Aug 4, 2014, 2:13:51 AM8/4/14
to Henry Lenzi, racket users list
Henry Lenzi wrote at 08/03/2014 11:52 PM:
> What I'm sensing is that you seem to be concerned about bugs with
> Racket Scheme's EVAL. Is that it?
> I do not understand what the problem with EVAL is. Would you please
> state clearly what the problems are?

Eval is one of the issues. Sorry I have to be very brief right now, but
a few problems with eval in general are:
* Prevents much static checking.
* Likely increased difficulty debugging.
* Often executes arbitrary code with privileges, which might be
corrupted due to accident or attack, which can be very bad.
* Prevents some optimization.
* Crutch that prevents learning better idioms.

Also, things like reading in a code file and looking for markers in it
is something we sometimes do (especially in, say, Emacs editing mode, in
which likely oopses are not so grave), but failure-prone.

Also, the code I saw was not idiomatic in, say, how it uses globals.

Anyway, it's good that Racket lets people experiment this way. The
concern I have in my mind is that newbies reading language forums often
get ideas about idiomatic programming from examples they see, and even
copy&adapt examples they see (maybe even evolving it into production
code, or blogging it where other newbies pick up on it...). People
should experiment as much as they liked, but I think it would be good to
if newbies knew when something they're looking at is an experiment
rather than (yet) considered best practice.

I appreciate your participation in the community, and your experimenting.

Matthew Flatt

unread,
Aug 4, 2014, 2:41:46 AM8/4/14
to Henry Lenzi, racket users list
At Mon, 4 Aug 2014 00:52:56 -0300, Henry Lenzi wrote:
> What I'm sensing is that you seem to be concerned about bugs with
> Racket Scheme's EVAL. Is that it?
> I do not understand what the problem with EVAL is. Would you please
> state clearly what the problems are?

While he didn't say so explicitly, I don't think that Neil is worried
about the implementation of `eval` within Racket. After all, `eval` is
at the heart of the implementation, and any program that you give to
Racket is going through `eval` whether or not the program calls the
`eval` function.

Speaking even more generally, I think "don't use `eval`" is intended in
much the same spirit as "don't write machine code":

Someone who says "don't write machine code" isn't worried about the
correctness of your x86 processor. They're concerned that by
programming in a relatively unstructured mode, you take on too much of
the burden of accommodating the run-time environment at the bit level,
whereas a higher-level language insulates you against may details.
(Also, a compiler can usually produce faster machine code than a human.)

Similarly, the problem with using `eval` is that you take on a burden
of managing binding at a relatively low symbolic level, and you have to
worry a lot about the dynamic context. As an extreme example, if you
write

(eval (list '+ x x))

intending to add `x` to itself, then you have to worry about whether
`+` still means addition --- as opposed to having `+` given a different
meaning by the time the `eval` is called. In contrast,

#lang racket
(define (f x) (+ x x))

means that `f` always adds its argument to itself, no matter what has
happened before. (And that `f` will be way faster than using `eval`.)


There are good and robust ways to use `eval` within Racket, just like
there are good and robust ways to generate machine code. But it's
exactly the job of a programming language to encode the good ways to do
things, and that's why so many on this list are eager to see you write

#lang prescription
HCTZ25 30 CP 1XD

instead of having "HCTZ25 30 CP 1XD" sit in a file that is sent in some
pieces through `eval`. We've learned that's just better to encode
things as languages.


Now, for someone in your position, the difference in this specific case
is subtle, because a doctor who writes

HCTZ25 30 CP 1XD

versus the "#lang prescription" above doesn't write `eval` either way.
It would seem that as the implementor of the language, you're the one
who properly has to deal with `eval`, and it makes sense for your
language implementation to call `eval`.

And yes... but it can be much better if you arrange for

#lang prescription
HCTZ25 30 CP 1XD

to become to something like

#lang racket/base
(import prescription/defs)
(hctz25 30 cp 1xd)

where `prescripton/defs` contains

(define hctz25 "Hydrochlorothiazide 25mg")
...

That is, instead of dynamically making "HCTZ25 30 CP 1XD" have the
effect of the Racket expression, actually compile it statically to the
Racket expression. Then, you're saying what you mean at a much higher
level what you intend to implement, and Racket can give you a lot more
help. For example, if a doctor accidentally types

#lang prescription
HCTZ25 30 CP add1

then instead of getting a weird run-time error about trying to use a
procedure as a string, then the doctor will get an error message that
`add1` is not a known identifier --- assuming that you did not intend
for `add1` to be included as part of the language. (If you intended to
include `add1`, then I think we can find any number of bindings that
you really do not intend for prescriptions authors to use.)

Again, it's possible to arrange for just the right bindings to be in
the namespace that you provide to `eval`. By always trying to write
things in terms of a language (as reflected by a module), however,
Racket can provide much better tools to help you say what you mean, and
it can provide a lot more efficiently and automatically.


There is a learning curve to doing this this way. We're working to make
that curve flatter, but he have a ways to go ourselves. But hopefully
that helps explain the general reaction to `eval` here.

Neil Van Dyke

unread,
Aug 4, 2014, 6:02:18 AM8/4/14
to Matthew Flatt, Henry Lenzi, racket users list

Matthew Flatt wrote at 08/04/2014 02:40 AM:
> While he didn't say so explicitly, I don't think that Neil is worried
> about the implementation of `eval` within Racket. After all, `eval` is
> at the heart of the implementation, and any program that you give to
> Racket is going through `eval` whether or not the program calls the
> `eval` function.

Correct. I breathe oxygen constantly, without thinking about it, but
I'd never use a fuel-air explosive to mow my lawn.

Neil V.

Matthias Felleisen

unread,
Aug 4, 2014, 10:14:56 AM8/4/14
to Neil Van Dyke, Matthew Flatt, Henry Lenzi, racket users list

On Aug 4, 2014, at 6:00 AM, Neil Van Dyke <ne...@neilvandyke.org> wrote:


Matthew Flatt wrote at 08/04/2014 02:40 AM:
While he didn't say so explicitly, I don't think that Neil is worried
about the implementation of `eval` within Racket. After all, `eval` is
at the heart of the implementation, and any program that you give to
Racket is going through `eval` whether or not the program calls the
`eval` function.

Correct.  I breathe oxygen constantly, without thinking about it, but I'd never use a fuel-air explosive to mow my lawn.


Off topic but I couldn't resist; see link/picture below from a recent trip to a workshop in Germany, where they use flamethrowers to burn off grass :-) 

Alexander D. Knauth

unread,
Aug 4, 2014, 2:12:00 PM8/4/14
to Henry Lenzi, racket users list
Then would something like this work?
#lang racket

(provide (all-defined-out)
         #%datum #%top
         (rename-out [new-module-begin #%module-begin]))

(define-syntax-rule
  (new-module-begin med-thing ...)
  (#%module-begin (displayln (parse-meds (list med-thing ...)))))

(define (parse-meds lst)
  (match lst
    [(list) ""]
    [(list-rest MED QUANT FORM POS (? inst? INST) rest)
     (~a MED " " line " " QUANT " " FORM "\n" POS "\n" INST "\n" (parse rest))]
    [(list-rest MED QUANT FORM POS rest)
     (~a MED " " line " " QUANT " " FORM "\n" POS "\n" (parse rest))]))

(define hctz25 "Hydrochlorothiazide 25mg")
(define simva20 "Simvastatin 20mg")
(define pl "pills")
(define 1xd "Take 1 pill P.O. 1x/day")
(define 1xn "Take 1 pill P.O. 1x at night")
(define INSTOMZ "half an hour before breakfast, with a glass of water")
(define line "-----------")

(define (inst? x)
  (equal? x INSTOMZ))

Alexander D. Knauth

unread,
Aug 4, 2014, 2:18:00 PM8/4/14
to Alexander D. Knauth, Henry Lenzi, racket users list
Oh sorry I meant this for parse-meds:
(define (parse-meds lst)
  (match lst
    [(list) ""]
    [(list-rest MED QUANT FORM POS (? inst? INST) rest)
     (~a MED " " line " " QUANT " " FORM "\n" POS "\n" INST "\n" (parse-meds rest))]
    [(list-rest MED QUANT FORM POS rest)
     (~a MED " " line " " QUANT " " FORM "\n" POS "\n" (parse-meds rest))]))

Henry Lenzi

unread,
Aug 4, 2014, 7:23:58 PM8/4/14
to racket users list
I was just wondering, Neil. what your experience in "production for
pharmaceutical prescriptions/labeling/instructions" software would be.

I'd be glad to read some stuff you've published or other software
solutions, if it's not proprietary software. If it is, what companies
have you worked for in the health sector?

Regards,
Henry Lenzi

Henry Lenzi

unread,
Aug 4, 2014, 7:44:39 PM8/4/14
to Racket list
Hi Neil --
Thanks for the answer.
Let's see...

* Prevents much static checking. ----> not really an issue in this
case (I don't see it).

* Likely increased difficulty debugging ---> true.

* Often executes arbitrary code with privileges, which might be
corrupted due to accident or attack, which can be very bad. --> That's
bad. But see my comment about the environment I'm in. User input
validation helps here.

* Prevents some optimization. ---> not really necessary. Prescriptions
are short, to worry about optimizations here, with today's machines,
doesn't seem a real issue.

* Crutch that prevents learning better idioms. ---> then whatever
happend to symbolic computation? Are we to program like Perl people
do?

It seems there are very good reasons to avoid eval. However, they seem
to apply to larger systems in a different environment.
I'm not out to write a large system for a large hospital service in a
secure setting.
By the way, if you guys had any idea of the buggy stuff people sell to
the health sector. The atrocious VB, MFC C++, Java... I'm not even
goint to mention security..

The use of EVAL does not seem to hamper the creation of a
syntax-validation parser, at a latter time.

Best regards,
Henry Lenzi

Neil Van Dyke

unread,
Aug 4, 2014, 8:08:58 PM8/4/14
to Henry Lenzi, racket users list
Henry Lenzi wrote at 08/04/2014 07:21 PM:
> I was just wondering, Neil. what your experience in "production for
> pharmaceutical prescriptions/labeling/instructions" software would be.
>
> I'd be glad to read some stuff you've published or other software
> solutions, if it's not proprietary software. If it is, what companies
> have you worked for in the health sector?

There have been many decades of work in software engineering for
military/aerospace/datacommunications, which gives some background that
can also be applied to, say, medical informatics.

For one example familiar to me, I worked on software tools and
methodology that were used for things like (to give one specific, public
example) designing the cockpit system for a particular model of military
aircraft. Some of my colleagues from back then later went to work on
medical devices, which share some requirements for correctness and
robustness.

The fields of medicine have ongoing tremendous accomplishments. Many of
the roles, such as physicians and pharma scientists, require immense
training and discipline. Still, as medical fields get more into areas
of informatics and of process, my understanding is that they are
currently learning from more established fields. For one example: the
widely-publicized finding that hospital staff following a "pre-flight
checklist" each time when hooking up a patient lowered infection rates
greatly. That's many decades behind what people who work on aviation
process have further found about process.

I'm not sure how to connect this general to individual computer
programming practices, except to say that, in clusters of people who
have done such-and-such kind of production work, I think that there is
often general agreement about some of the best practices and pitfalls.
For an example bringing us back to this email thread, many people on
this email list come from different backgrounds of software development,
to be enthusiasts of an especially powerful dynamic language platform,
yet it seems that the majority(?) of us arrived at a wariness of "eval"
independently, even though I'm not aware of any textbook that says
"don't use eval" (textbooks often accidentally suggest the opposite).

BTW, "Don't use eval" is just one tip of many, and I didn't intend to
spend so much text on it in this thread.

Neil Van Dyke

unread,
Aug 4, 2014, 8:44:59 PM8/4/14
to Henry Lenzi, Racket list
Henry Lenzi wrote at 08/04/2014 07:43 PM:
> By the way, if you guys had any idea of the buggy stuff people sell to
> the health sector. The atrocious VB, MFC C++, Java... I'm not even
> goint to mention security..

Heh. I have seen some of that, and actually suggested to one of my
consulting clients that they consider diversifying into this application
domain. I suspect that one "dream team" would have a mix of domain
experts, people who understand the legacy/contemporary software systems
and history, a couple top architects/gurus, and solid software engineers
and human factors engineers who are sharp and flexible enough to work
within the framework that the architects/gurus lead.

(I separate out architects/gurus for this particular field because there
seems to be a need to shake things up right now with technical
direction. However, I *don't* mean an antiquated chief programmer
model, which I think led many to view software development as top-down
management of clerical workers, especially in corporate MIS-like shops,
and which I suspect has been a big contributor to many gazillion-dollar
IT failures.)

Matthias Felleisen

unread,
Aug 5, 2014, 6:44:38 PM8/5/14
to Neil Van Dyke, Matthew Flatt, Henry Lenzi, racket users list

On Aug 4, 2014, at 6:00 AM, Neil Van Dyke <ne...@neilvandyke.org> wrote:


Matthew Flatt wrote at 08/04/2014 02:40 AM:
While he didn't say so explicitly, I don't think that Neil is worried
about the implementation of `eval` within Racket. After all, `eval` is
at the heart of the implementation, and any program that you give to
Racket is going through `eval` whether or not the program calls the
`eval` function.

Correct.  I breathe oxygen constantly, without thinking about it, but I'd never use a fuel-air explosive to mow my lawn.


Off topic but I couldn't resist; see picture below from a recent trip to a workshop in Germany, where they use flamethrowers to burn off grass :-) 



Eli Barzilay

unread,
Aug 9, 2014, 7:32:58 AM8/9/14
to Neil Van Dyke, Racket Users
I think that I ran into a nice way to discourage eval except when
needed: the rule of thumb is to only use eval when you need to evaluate
any arbitrary (Racket) expression. It sounds simplistic but it covers
lots of cases that make newbies run to eval:

* I just want to get the value of a variable whose name is held in x

* More common: I have a symbol/string that names a function, I just need
to call that function

* I need to keep an update-able mapping from names to values, just like
what the toplevel does

* I want to let people write an arithmetic expression instead of a
number

In such cases questions like "do you need allow calling all functions",
and "do you need to handle lambda expressions" have negative answers.



On Sun, Jul 27, 2014 at 4:16 PM, Neil Van Dyke <ne...@neilvandyke.org> wrote:
> Maybe there should be a periodic public service announcement about not using
> "eval". This time I will communicate in FAQ format:
>
> Q: How do I use eval?
> A: Don't use eval.
>
> Q: But don't so many academic books feature eval prominently, so doesn't
> that mean I should use try to eval?
> A: Those books use eval for pedagogic reasons, or because the author is
> enamored of some theoretical appeal of eval, or because the author wants to
> watch the world burn. Don't use eval.
>
> Q: But, but, but, I am just starting to learn, and eval seems to do what I
> need.
> A: Eval is almost certainly not what you want. Learn how to use the other
> basics effectively. Don't use eval.
>
> Q: I now am very comfortable with the language, I am aware that I should
> avoid eval in almost all cases, and I can tell you why eval is actually the
> right thing in this highly unusual case.
> A: Cool, that's why eval is there.
>
> Neil V.
>
>
> ____________________
> Racket Users list:
> http://lists.racket-lang.org/users



--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://barzilay.org/ Maze is Life!

Neil Van Dyke

unread,
Aug 9, 2014, 8:29:32 AM8/9/14
to Eli Barzilay, Racket Users
Sounds like a good rule of thumb. Two suggestions to add:

* Maybe there could also be a second rule of thumb, like, "If you need
arbitrary Racket expressions, then consider whether you can do it with
one of the following patterns: [list some patterns involving
combinations of syntax extension, custom #lang, dynamic requires,
considering whether config files can actually be compile-time #lang,
etc.]" This is less important than the first rule of thumb.

* When we list typical newbie cases that don't actually require "eval",
we can expect that newbie will immediately want an example of the
non-"eval" way to do that typical thing. At the very least, an example
showing, say, good use of hashes in parameters, with a sensible thin
abstraction layer over it, for that case. These examples would be
tedious to work through and write up well, but someday some
knowledgeable and benevolent person will do it. (I am not this person.
Book royalties aren't enough to ease the pain. I'd rather that newbies
just never heard of "eval" or were scared away from it, rather than
having to talk them down off the ledge all the time.)

Neil V.

Sean Kanaley

unread,
Aug 9, 2014, 10:11:52 AM8/9/14
to Neil Van Dyke, Eli Barzilay, Racket Users
There's a simple enough example I think: apply with keyword parameters. Apply has that built-in..sort of...but the list is supposed to be provided inline to APPLY, seemingly requiring apply to be applied (e.g. (apply apply (cons *thefunctiontoapply* params))), except keywords can't be expressions anyway. I have a bunch of card definitions for Dominion with many defaults:

(struct card (... actions buys ...))

(define (make-card ... #:actions actions #:buy buys ...)
  ...)

The non-keyword-requiring way is

(define CARDS
  (map (\ (lst) (apply make-card lst))
          '([... 1 1 ...]
           [... 2 0 ...])))

The keyword way is

;ns is namespace
(mapply (\ (lst) (eval `(apply make-card ',(car l) ,@(cdr l)) ns))
        '([(...) #:actions 1 #:buys 1 ...]))

Short of making a big macro to take some exact format and get it to work with keywords and all that, eval seems to be just what is needed.

Sean Kanaley

unread,
Aug 9, 2014, 10:12:51 AM8/9/14
to Neil Van Dyke, Eli Barzilay, Racket Users
Sorry, couple typos: mapply = map and l = lst.

Alexander D. Knauth

unread,
Aug 9, 2014, 4:28:37 PM8/9/14
to Sean Kanaley, Eli Barzilay, racket users list, Neil Van Dyke
Just for fun, I made a function to do this the “non-eval” way, and it was more complicated than I would have thought, although maybe I was overcomplicating it a bit?  

Matthew Flatt

unread,
Aug 10, 2014, 4:02:08 AM8/10/14
to Sean Kanaley, Racket Users
I think you're looking for `keyword-apply`.

It's true that `eval` works as way to get reflective operations in
general, but it's better (again, for error checking and for efficiency)
when a language construct is accompanied with specific reflective
operations. In the case of keyword arguments, those operations include
`make-keyword-procedure`, `keyword-apply`, and
`procedure-reduce-keyword-arity`.

It's not always obvious which operations to include, and
`procedure-reduce-keyword-arity`, for one, wasn't included originally.
I think I might also have trouble defining "reflective operation"
precisely, as opposed to having constructs that support abstraction
more directly (such as allowing the superclass position of a `class`
form to be an expression). But if `keyword-apply` didn't exist, then
this example would make me think that some form of abstraction was
missing for keyword arguments, instead of seeming like a good use of
`eval`.

Eli Barzilay

unread,
Aug 10, 2014, 5:16:09 AM8/10/14
to Neil Van Dyke, Racket Users
On Sat, Aug 9, 2014 at 8:27 AM, Neil Van Dyke <ne...@neilvandyke.org> wrote:
> Sounds like a good rule of thumb. Two suggestions to add:
>
> * Maybe there could also be a second rule of thumb, like, "If you need
> arbitrary Racket expressions, then consider whether you can do it
> with one of the following patterns: [list some patterns involving
> combinations of syntax extension, custom #lang, dynamic requires,
> considering whether config files can actually be compile-time #lang,
> etc.]" This is less important than the first rule of thumb.

That would be a good bottom addition -- after all the discouraging is
done since (IIUC) your targeting valid eval cases in ways that are
similar to it.


> * When we list typical newbie cases that don't actually require
> "eval", we can expect that newbie will immediately want an example
> of the non-"eval" way to do that typical thing. At the very least,
> an example showing, say, good use of hashes in parameters, with a
> sensible thin abstraction layer over it, for that case. These
> examples would be tedious to work through and write up well, but
> someday some knowledgeable and benevolent person will do it. (I am
> not this person. [...]

+1, in general, but it sounds like a hard thing to do. IME, the big
problem is that usually when people get to ask about how to do something
with eval, that something is already an abstraction of their real
motivation. The best example of that is the common case of trying to
get from a symbol/string that names a binding to its value -- it could
be that they need to use a hash table, or maybe they don't know that
they can use functions (as in +) directly instead of names ('+), or they
don't know how to use symbols and try to map them to integers in an
attempt to implement some enum-like thing, etc. I've done a quick scan
of eval-tagged questions on SO (crossed with `python', `javascript', and
`lisp'), and I couldn't find questions that could be grouped.

--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://barzilay.org/ Maze is Life!

Eli Barzilay

unread,
Aug 10, 2014, 5:23:37 AM8/10/14
to Matthew Flatt, Racket Users
On Sun, Aug 10, 2014 at 3:59 AM, Matthew Flatt <mfl...@cs.utah.edu> wrote:
>
> It's true that `eval` works as way to get reflective operations in
> general, but it's better (again, for error checking and for
> efficiency) when a language construct is accompanied with specific
> reflective operations. [...] But if `keyword-apply` didn't exist,
> then this example would make me think that some form of abstraction
> was missing for keyword arguments, instead of seeming like a good use
> of `eval`.

+7 -- it's a nice demonstration of what I started with: use eval only
when you need the ability to evaluate all expressions, is this what you
need? -- No, I just want to apply functions with an unknown keyword...

It's interesting to note that in Javascript there are many common uses
of eval, which are indeed pointers at missing features of the language.
(And only in rare cases the features get added -- as in the case of
parsing JSON (which pointed to a missing `read' feature).)

--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://barzilay.org/ Maze is Life!

Sean Kanaley

unread,
Aug 10, 2014, 10:40:27 AM8/10/14
to Eli Barzilay, Matthew Flatt, Racket Users
***The ultimate (programming) concern is what will produce the highest average correct-and-useful-running-program-output per second over my lifespan.***

(philosophical extensions: provided it doesn't hurt other people, unless they are "bad", where bad = ...etc...)

Or anyone else who programs. The average decreases when something new is learned, and increases later as a payoff from the new knowledge (ideally...). This is especially important to experts in other fields who want a quick solution instead of a theoretically maximally correct and beautiful and least upsetting to experts solution.

So I didn't need keyword-apply. I had the following choices:

1. build literal expression, call eval (~1 min dev time)

2. search documentation or google for "apply keyword", reach page of documentation, *carefully* read all relevant-sounding functions on it, choose keyword apply, THEN implement it (~10+ min?) (in reality after trying apply for a bit since it seems like it would work, and for fear of just using eval and being branded a C programmer, eventually concluding it can't work = additional 5 min)

3. make a mistake with step 2, make post to user's list asking about this case, receive feedback that it wasn't necessary to use it, go back and fix code to be "correct" (unsure of time to type the first post, but the overall energy spent on this process exceeds #1 and #2 for sure)

In my case, I'm glad I now know about keyword-apply because I will be using Racket until I die. Those 15 minutes will *hopefully* save over 15 minutes by the end of my life. They might not though, and time now > time later, but I'm still glad because I enjoy programming as a hobby and want to be good at it, but in terms of maximizing output I should have just used eval.

Taken further, there is some optimal level of knowledge that allows for all tasks that need to be completed to be completed as quickly and accurately as possible, where further knowledge represents time spent wasted acquiring it. Professionals in fields other than programming itself will probably have a low level of optimal knowledge, and the attitude that some seem to have about "dumb newbies with their dumb evals" is incorrect. They should possibly do whatever is as fast as possible, regardless of how bad the code is.

Matthew Flatt

unread,
Aug 11, 2014, 2:09:18 AM8/11/14
to Sean Kanaley, Racket Users
+1

In the grand scheme of things, using `eval` to solve a problem (because
you want to get something done now) is nowhere near as bad as, say,
using/building an interpreter that is implemented in C (because I want
to get something done "now", circa 1995).

:)

Pierpaolo Bernardi

unread,
Aug 11, 2014, 3:16:53 AM8/11/14
to Matthew Flatt, Racket Users
On Mon, Aug 11, 2014 at 8:07 AM, Matthew Flatt <mfl...@cs.utah.edu> wrote:
> +1
>
> In the grand scheme of things, using `eval` to solve a problem (because
> you want to get something done now) is nowhere near as bad as, say,

but, to come back to the original question, in order to not confuse
further the OP: in this case eval was NOT getting anything done. On
the contrary, it was creating a nightmare out of a trivial task.
Reply all
Reply to author
Forward
0 new messages