From: are
Subject: Array and Hash-Table References
Date: 
Message-ID: <1190241964.005248.273810@d55g2000hsg.googlegroups.com>
What are the pros and cons of a Lisp in which (AREF x 3) and (GETHASH
'c y), for example, becomes (x 3) and (y 'c), respectively?  The
latter are more concise; is there a down side?

From: Raffael Cavallaro
Subject: Re: Array and Hash-Table References
Date: 
Message-ID: <2007091919594350073-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2007-09-19 18:46:04 -0400, are <·········@gmx.net> said:

> What are the pros and cons of a Lisp in which (AREF x 3) and (GETHASH
> 'c y), for example, becomes (x 3) and (y 'c), respectively?  The
> latter are more concise; is there a down side?

Seems like even proposing this assumes a lisp-1. i.e., you can't also have a
function named x if (x 3) means (aref x 3).
From: Kent M Pitman
Subject: Re: Array and Hash-Table References
Date: 
Message-ID: <ur6ktso2t.fsf@nhplace.com>
Raffael Cavallaro <················@pas-d'espam-s'il-vous-plait-mac.com> writes:

> On 2007-09-19 18:46:04 -0400, are <·········@gmx.net> said:
> 
> > What are the pros and cons of a Lisp in which (AREF x 3) and (GETHASH
> > 'c y), for example, becomes (x 3) and (y 'c), respectively?  The
> > latter are more concise; is there a down side?
> 
> Seems like even proposing this assumes a lisp-1. i.e., you can't also have a
> function named x if (x 3) means (aref x 3).

It's also low-error-checking.  Especially in the case of GETHASH, since
every possible argument to GETHASH is a valid arg, the system would never
tell you if you'd been editing an ordinary function call on h, a hash
table, like:
 (foo h 3)
and had accidentally deleted foo, leaving
 ( h 3)
in your buffer.  It would just return a wrong value.  At least in the case
of having to do
 (ref h 3)
where ref might be generic, you get some case-marking that an access is
intended.

As to whether the unspoking issue of whether the arg order of GETHASH is
right, it's plainly not.  But one can trivially define an accessor that
fixes that and ignore GETHASH.

Btw, another issue that may not be obvious is that in Maclisp, which was
a Lisp2, arrays WERE funcallable.  That's actually a different question
than whether their names can live in the operator position.  One could
let an array masquerade as a function and that was sometimes useful.
You still had to use FUNCALL, of course.
From: ············@gmail.com
Subject: Re: Array and Hash-Table References
Date: 
Message-ID: <1190314723.251912.182970@k79g2000hse.googlegroups.com>
On Sep 19, 5:46 pm, are <·········@gmx.net> wrote:
> What are the pros and cons of a Lisp in which (AREF x 3) and (GETHASH
> 'c y), for example, becomes (x 3) and (y 'c), respectively?  The
> latter are more concise; is there a down side?

We've heard some cons, but on the pro side, functions and the data
structures you mention alike are mappings.  It'd be nice to abstract
away whether that mapping is calculated by a function or stored in an
object.
From: Rob Warnock
Subject: Re: Array and Hash-Table References
Date: 
Message-ID: <JbidnXlzmMMo127bnZ2dnUVZ_o2vnZ2d@speakeasy.net>
············@gmail.com <············@gmail.com> wrote:
+---------------
| On Sep 19, 5:46 pm, are <·········@gmx.net> wrote:
| > What are the pros and cons of a Lisp in which (AREF x 3) and (GETHASH
| > 'c y), for example, becomes (x 3) and (y 'c), respectively?  The
| > latter are more concise; is there a down side?
| 
| We've heard some cons, but on the pro side, functions and the data
| structures you mention alike are mappings.  It'd be nice to abstract
| away whether that mapping is calculated by a function or stored in an
| object.
+---------------

O.k., o.k., have it your way:

    > (defmacro define-funcallable-array (name dimensions
                                          &rest array-init-args)
        (let ((lex-name
               (intern (concatenate 'string (symbol-name :*LEXVAR-FOR-)
                                            (symbol-name name)
                                            (symbol-name :*))
                       (symbol-package name)))
              (setf-name
               (intern (concatenate 'string (symbol-name :setf-)
                                            (symbol-name name))
                       (symbol-package name))))
          `(progn
            (defparameter ,lex-name
                          (make-array ,dimensions ,@array-init-args))
            (define-symbol-macro ,name ,lex-name)
            (defun ,name (&rest indices)
              (apply #'aref ,name indices))
            ;; Awkward, but the only alternative is reversal, like GETHASH.
            (defun ,setf-name (index-list new-value)
              (setf (apply #'aref ,name index-list) new-value)))))

    DEFINE-FUNCALLABLE-ARRAY
    > (loop for i below 3 collect
        (loop for j below 5 collect
          (+ 100 (* i 10) j)))

    ((100 101 102 103 104) (110 111 112 113 114) (120 121 122 123 124))
    > (define-funcallable-array foo '(3 5) :initial-contents *)

    SETF-FOO
    > foo

    #2A((100 101 102 103 104) (110 111 112 113 114) (120 121 122 123 124))
    > (foo 1 2)

    112
    > (setf-foo (list 1 2) 3737)

    3737
    > (foo 1 2)

    3737
    > foo

    #2A((100 101 102 103 104) (110 111 3737 113 114) (120 121 122 123 124))
    > 

Happy now?!?


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kyle McGivney
Subject: Re: Array and Hash-Table References
Date: 
Message-ID: <1190300644.908440.52520@19g2000hsx.googlegroups.com>
On Sep 19, 6:46 pm, are <·········@gmx.net> wrote:
> What are the pros and cons of a Lisp in which (AREF x 3) and (GETHASH
> 'c y), for example, becomes (x 3) and (y 'c), respectively?  The
> latter are more concise; is there a down side?

I'm sure this conversation has hit this board a few times before, so
stop me if I'm posting an old idea:

what about the syntax #z(a 3) for (aref a 3)?

(defun access-array (stream char arg)
  (declare (ignore char arg))
  (let ((args (read stream)))
    `(aref ,(first args) ,(second args))))

(set-dispatch-macro-character #\# #\z #'access-array)

You could either try and write a #y for hash tables or extend this
somehow to check the type of the data...

Kyle
From: Rainer Joswig
Subject: Re: Array and Hash-Table References
Date: 
Message-ID: <joswig-483EFF.18522920092007@news-europe.giganews.com>
In article <·······················@19g2000hsx.googlegroups.com>,
 Kyle McGivney <·······@gmail.com> wrote:

> On Sep 19, 6:46 pm, are <·········@gmx.net> wrote:
> > What are the pros and cons of a Lisp in which (AREF x 3) and (GETHASH
> > 'c y), for example, becomes (x 3) and (y 'c), respectively?  The
> > latter are more concise; is there a down side?
> 
> I'm sure this conversation has hit this board a few times before, so
> stop me if I'm posting an old idea:

It is called 'funcallable data'. One place where Common Lisp has
it is 'Generic Functions'. Generic Functions are both
CLOS objects and Functions. See here for an example usage:
http://doc.gold.ac.uk/~mas01cr/papers/ilc2007/sequences-20070301.pdf

It is not current practice and introduction
would confuse people. There is some benefit of stable
coding styles and not introducing more
obfuscation.

> 
> what about the syntax #z(a 3) for (aref a 3)?
> 
> (defun access-array (stream char arg)
>   (declare (ignore char arg))
>   (let ((args (read stream)))
>     `(aref ,(first args) ,(second args))))
> 
> (set-dispatch-macro-character #\# #\z #'access-array)
> 
> You could either try and write a #y for hash tables or extend this
> somehow to check the type of the data...
> 
> Kyle

-- 
http://lispm.dyndns.org
From: Alan Crowe
Subject: Re: Array and Hash-Table References
Date: 
Message-ID: <86ps0dtmzy.fsf@cawtech.freeserve.co.uk>
are <·········@gmx.net> inquires
> What are the pros and cons of a Lisp in which (AREF x 3) and (GETHASH
> 'c y), for example, becomes (x 3) and (y 'c), respectively?  The
> latter are more concise; is there a down side?

Let me see if I've understood your question. Think about the
kind of code in which you want to generate a hash table that
remembers the results of applying a function to various
arguments given in an array. One might code it like this

(defun remember1 (a f)
  (let ((ht (make-hash-table)))
    (dotimes (i (length a) ht)
      (setf (gethash (aref a i) ht)
            (funcall f (aref a i))))))

Sample output

(gethash 4
         (remember1 #(3 4 5)
                    (lambda(x)(* x x))))
=> 16,T

The code clunks a little and you are asking about replacing

      (setf (gethash (aref a i) ht)
            (funcall f (aref a i))))))

with

        (setf (ht (a index))
              (f (a index)))))))

You can explore this issue for yourself. Load these
defintions:

(defun process (name)
  `(,name (&rest args)
    `(operate ,',name ,@args)))

(defmacro with-ops (names &body code)
  `(macrolet ,(mapcar #'process names)
    ,@code))

(defun operate (operator &rest args)
  (etypecase operator
    (function (apply operator args))
    (hash-table (gethash (first args) operator))
    (array (apply #'aref operator args))))

(defun (setf operate)(new-value operator &rest args) 
  (etypecase operator
    (array
     (setf (apply #'aref operator args) new-value))
    (hash-table
     (setf (gethash (first args) operator) new-value))))

They allow you to write

(defun remember2 (a f)
  (let ((ht (make-hash-table)))
    (with-ops (a f ht)
      (dotimes (i (length a) ht)
        (setf (ht (a i))
              (f (a i)))))))

which works just like remember1.

I think the issues would really come into focus as a project
moved into maintenance. I could imagine an edit war breaking
out as some programmers add comments to help them understand
the code.

(setf (#|look up|# ht (#|array|# a i))
      (#|function|# f (#|array|# a i)))

Perhaps a truce would be established with a naming
convention

(setf (hash-table-ht (array-a i))
      (function-f (array-a i)))

or perhaps I have an over-active imagination.

These issues are issues of human psychology, not computer
science, so arm chair theorising is apt to be especially
ineffective. Fire up your development environment and write
some code. Come back with some examples drawn from life.

Alan Crowe
Edinburgh
Scotland