Re: Cond, and abusing or

2010-01-16 Thread Meikel Brandmeyer
Hi,

Am 16.01.2010 um 01:48 schrieb Scott Burson:

 Certainly, this is a very common idiom in Common Lisp and other older
 dialects.  I guess there are a few people who don't like it, but a lot
 of us do it routinely.  You'll even see stuff like
 
  (or (try-to-construct-a-foo)
   (error Couldn't construct a foo))

Just be aware that if a nil or false is a valid answer this approach will fail.

Sincerely
Meikel

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Cond, and abusing or

2010-01-15 Thread Simon Brooke
There's an old programmers hack that works in many languages of
abusing the logical or operator to try a sequence of operations until
one returns something useful. It appears that this works in Clojure,
too.

The reason I tried it is that I'm unhappy with Clojure's
implementation of cond. Consider the following interaction:

You are in a shed.
There is a box here
There is a knife here
= open the box
You open the box.
There is a knife in the box
= Take the knife out of the box
You take the knife out of the box

Now, consider a recursive repertoire structure in which each element
is a tuple {token, before-action, sub-repertoire, after-action} a
subset of which is like this

((take
 ()
 ((the
(bind-target-and-continue player (cdr line) (caddr
repertoire) context)
((out () () (take-from-container player (cdr line)
(caddr repertoire) context))
))
(take-from-environment player (cdr line) (caddr repertoire)
context)))

The action parts may internally recurse into the interpreter; so for
example bind-target-and-continue puts the token that follows the
into the context as the target and then re-enters the interpreter with
the remainder of the line and the sub-repertoire

So given 'take the knife out of the box'

== at take there is no before action, so we interpret the sub-
repertoire
 at the there is a before action, so we bind knife as target,
and interpret the rest of the line with the sub-repertoire
== at out there is no before-action or sub-repertoire, so we
evaluate the after-action which tells us to treat what's left of the
line (of the box) as a container specifier, locate a container that
matches that description in the environment, and take the knife out of
it, rather than the knife in the environment

But given just 'take the knife'

== at take there is no before action, so we interpret the sub-
repertoire
 at the there is a before action, so we bind knife as target,
and interpret the rest of the line with the sub-repertoire
 but there is no rest-of-line, so interpreting it returns null
== so we interpret the post action on take, and take the knife from
the environment, not the one in the box.

You can build up remarkably convincing interpreters for a subset of
imperative English with this and a few Eliza style tricks. In portable
standard lisp one would write

(cond
  ((eval before-action))
  ((interpret player sub-repertoire context))
  ((eval after-action)))

This is because each clause of the cond statement was an implicit do
list, so

(let ((a 'foo)(b nil))
  (cond
(a)
(b)))

= foo

Each of a and b are evaluated at most once (as a has a non-nil binding
in this case b is not evaluated at all).

To achieve this with Clojure's cond I have to do either

(let [a 'foo b nil]
  (cond
a a
b b))

= foo

in which case a is evaluated twice; or

(let [a 'foo b nil]
  (let [value-of-a a value-of-b b]
(cond
  (not (= nil value-of-a))
  value-of-a
  (not (= nil value-of-b))
  value-of-b)))

= foo

which only evaluates a once but it always evaluates b whether it needs
to or not, /and/ it's fugly and hard to read, /and/ it's very likely
inefficient (but someone more fluent in Clojure could probably replace
my (not (= nil thing)) with something cleaner); or else

(let [a 'foo b nil]
  (or a b))

= foo

which is simple and easy to read, but is exploiting the left-to-right
evaluation strategy of the or operator. It isn't (or ought not to need
to be) part of the contract of the or operator that it evaluates left
to right. On a massively parallel machine, all branches of the or
might be explored simultaneously. So this sort of hack leaves me
feeling dirty.

Comments?

Is there (once again) something more elegant I've missed?
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Cond, and abusing or

2010-01-15 Thread Rich Hickey


On Jan 15, 5:02 pm, Simon Brooke still...@googlemail.com wrote:
 There's an old programmers hack that works in many languages of
 abusing the logical or operator to try a sequence of operations until
 one returns something useful. It appears that this works in Clojure,
 too.

 The reason I tried it is that I'm unhappy with Clojure's
 implementation of cond. Consider the following interaction:

 You are in a shed.
     There is a box here
     There is a knife here
 = open the box
 You open the box.
     There is a knife in the box
 = Take the knife out of the box
 You take the knife out of the box

 Now, consider a recursive repertoire structure in which each element
 is a tuple {token, before-action, sub-repertoire, after-action} a
 subset of which is like this

     ((take
          ()
          ((the
             (bind-target-and-continue player (cdr line) (caddr
 repertoire) context)
             ((out () () (take-from-container player (cdr line)
 (caddr repertoire) context))
             ))
         (take-from-environment player (cdr line) (caddr repertoire)
 context)))

 The action parts may internally recurse into the interpreter; so for
 example bind-target-and-continue puts the token that follows the
 into the context as the target and then re-enters the interpreter with
 the remainder of the line and the sub-repertoire

 So given 'take the knife out of the box'

 == at take there is no before action, so we interpret the sub-
 repertoire
  at the there is a before action, so we bind knife as target,
 and interpret the rest of the line with the sub-repertoire
 == at out there is no before-action or sub-repertoire, so we
 evaluate the after-action which tells us to treat what's left of the
 line (of the box) as a container specifier, locate a container that
 matches that description in the environment, and take the knife out of
 it, rather than the knife in the environment

 But given just 'take the knife'

 == at take there is no before action, so we interpret the sub-
 repertoire
  at the there is a before action, so we bind knife as target,
 and interpret the rest of the line with the sub-repertoire
  but there is no rest-of-line, so interpreting it returns null
 == so we interpret the post action on take, and take the knife from
 the environment, not the one in the box.

 You can build up remarkably convincing interpreters for a subset of
 imperative English with this and a few Eliza style tricks. In portable
 standard lisp one would write

     (cond
       ((eval before-action))
       ((interpret player sub-repertoire context))
       ((eval after-action)))

 This is because each clause of the cond statement was an implicit do
 list, so

     (let ((a 'foo)(b nil))
       (cond
         (a)
         (b)))

 = foo

 Each of a and b are evaluated at most once (as a has a non-nil binding
 in this case b is not evaluated at all).

 To achieve this with Clojure's cond I have to do either

     (let [a 'foo b nil]
       (cond
         a a
         b b))

 = foo

 in which case a is evaluated twice; or

     (let [a 'foo b nil]
       (let [value-of-a a value-of-b b]
         (cond
           (not (= nil value-of-a))
           value-of-a
           (not (= nil value-of-b))
           value-of-b)))

 = foo

 which only evaluates a once but it always evaluates b whether it needs
 to or not, /and/ it's fugly and hard to read, /and/ it's very likely
 inefficient (but someone more fluent in Clojure could probably replace
 my (not (= nil thing)) with something cleaner); or else

     (let [a 'foo b nil]
       (or a b))

 = foo

 which is simple and easy to read, but is exploiting the left-to-right
 evaluation strategy of the or operator. It isn't (or ought not to need
 to be) part of the contract of the or operator that it evaluates left
 to right. On a massively parallel machine, all branches of the or
 might be explored simultaneously. So this sort of hack leaves me
 feeling dirty.

 Comments?

 Is there (once again) something more elegant I've missed?

or has left-to-right and short-circuiting in its contract and will
never be executed in parallel (any parallel or would be a different
thing). The 'hack' is fine, and clean. As far as cond, as in many
areas, like 'let', Clojure opts out of the increased verbosity and
clutter of the additional grouping, admittedly losing the facility you
desire. It's a tradeoff I think serves the common case well.

Note that condp supports a ternary clause form that shovels the test
expr into the result expr (this more of a hack for your purposes):

(let [a 'foo b nil]
  (condp #(or %1 %2) nil
   a : identity
   b : identity))

= foo

There has been some talk of adding : to cond also.

Rich
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from 

Re: Cond, and abusing or

2010-01-15 Thread Scott Burson
On Jan 15, 2:02 pm, Simon Brooke still...@googlemail.com wrote:
 There's an old programmers hack that works in many languages of
 abusing the logical or operator to try a sequence of operations until
 one returns something useful. It appears that this works in Clojure,
 too.

Certainly, this is a very common idiom in Common Lisp and other older
dialects.  I guess there are a few people who don't like it, but a lot
of us do it routinely.  You'll even see stuff like

  (or (try-to-construct-a-foo)
   (error Couldn't construct a foo))

-- Scott
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en