[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

destructuring-case and rational type expressions

Jim Newton

5/24/2016 8:47:00 AM

This month I presented a paper at ELS (http://www.european-lisp-sym...)
on some work I've been doing with type checking related to CL sequences.

One of the cool results is yet another macro named destructuring-case which uses
destructuring lambda lists as well as type declarations to "match" a given sequence
and branch to the appropriate clause. Here is a simple example:

(destructuring-case DATA
((name &key x (y 0))
(declare (type string name)
(type x list)
(type y fixnum))
...)
((name &key (x "") (y 0.0))
(declare (type (or symbol string) name)
(type string x)
(type number y))
...)
((name &rest others)
...))

If anyone is interested in looking at the ELS article or a more in-depth technical report
about the research. Here is a link: https://www.lrde.epita.fr/wiki/Publications/new...

If anyone is interested in looking into the code: here is a link to that:
https://gitlab.lrde.epita.fr/jnewton/regular-type-...

Let me know if you have questions, comments, or objections.
I'd be happy if someone finds it interesting or useful.
46 Answers

Sebastian Christ

5/24/2016 9:06:00 AM

0

On 2016-05-24 1:47, Jim Newton <jimka.issy@gmail.com> wrote:
> One of the cool results is yet another macro named destructuring-case which uses
> destructuring lambda lists as well as type declarations to "match" a given sequence
> and branch to the appropriate clause. Here is a simple example:
> [..snip..]

Is this DESTRUCTURING-CASE macro different from the one provided by ALEXANDRIA
(https://common-lisp.net/project/alexandria/draft/alexandria.html#Data-and-Co...)?

Regards,
Sebastian

--
Sebastian (Rudolfo) Christ
http://rudolfochrist...
GPG Fingerprint: 306D 8FD3 DFB6 4E44 5061
CE71 6407 D6F8 2AC5 55DD

Jim Newton

5/24/2016 12:29:00 PM

0

Yes, very different.
As I understand the alexandria destructuring-case, you have to provide a key
to tell the macro where to dispatch to.
The macro which I'm introducing here, matches its argument against the
first destructuring lambda list which matches according to structure and declared types.




On Tuesday, May 24, 2016 at 11:06:24 AM UTC+2, Sebastian Christ wrote:
> > One of the cool results is yet another macro named destructuring-case which uses
> > destructuring lambda lists as well as type declarations to "match" a given sequence
> > and branch to the appropriate clause. Here is a simple example:
> > [..snip..]
>
> Is this DESTRUCTURING-CASE macro different from the one provided by ALEXANDRIA
> (https://common-lisp.net/project/alexandria/draft/alexandria.html#Data-and-Co...)?
>
> Regards,
> Sebastian
>

Kaz Kylheku

5/24/2016 1:19:00 PM

0

On 2016-05-24, Jim Newton <jimka.issy@gmail.com> wrote:
> Yes, very different.
> As I understand the alexandria destructuring-case, you have to provide a key
> to tell the macro where to dispatch to.

But that makes it more useful. And it appears to reduce to the simple
non-key case if you use a fixed key, and use only that key in all the
cases.

(destructuring-case (cons :dummy whatever)
((:dummy . ( x y ) ...)))

> The macro which I'm introducing here, matches its argument against the
> first destructuring lambda list which matches according to structure and declared types.

I.e. you remove the refinement of adding the key dispatch to just the
bare, obvious way of doing doing cases based on destructuring.

Lispers have been reinventing case statements based on destructuring
binding for decades.

TXR Lisp tree-case:

http://www.nongnu.org/txr/txr-manpage.html#...

Here, I provide the refinement that a case can return the : object,
which causes fall-through to the next case.

This is a sort of band-aid for the problem that simple destructuring is
a bit of a downer compared to some sort of pattern matching. It's a very
inconspicuous band-aid, though.

Alexandria's key mechanism appears to have a similar motivation,
allowing the same thing: multiple cases with the same destructuring
pattern which are distinguished somehow.

destructuring-bind doesn't match any constant material in the template,
or any other attributes besides the cons tree structure. Variables must
be provided for every part that is matched. I called it tree-bind for
that reason, and because tree is a nice monosyllabic word.

Jim Newton

5/24/2016 1:42:00 PM

0

Does it use the types of the arguments in its decision of which clause to branch to?
Or does it rely only on the structure?

> TXR Lisp tree-case:
>
> http://www.nongnu.org/txr/txr-manpage.html#...
>

The cool thing, in my opinion, about this implementation is that it reads the type declarations and uses that in the decision making.

E.g.,
(destructuring-bind DATA
((a (b c))
(declare (type fixnum a b) (type string c))
...)
((a (b c) @optional (d ""))
(declare (type number a b) (type symbol c) (type string d))
...)
((a (b c))
(declare (type fixnum a b) (type list c))
...))

Grumpus

5/24/2016 2:47:00 PM

0

Kaz Kylheku wrote:

> And it appears to reduce to the simple non-key case if you use a
> fixed key, and use only that key in all the cases.

If that's how destructuring-case *really* works, the docs aren't any
good:

The clause whose case-keys matches car of key, as if by case, ccase,
or ecase, is selected, and FORMs are then executed with cdr of key
is destructured and bound by the destructuring-lambda-list.

Jim Newton

5/24/2016 3:25:00 PM

0

I was under the impression from looking at the code, and some examples that it didn't take types into account.

Another cool feature of the one I present is that it flags unreachable branches. I.e. if there's a branch which cannot be reached because every list which matches it also matches some previous clause, then slime/sbcl will flag it as deleting unreachable code.

Jim Newton

5/24/2016 3:39:00 PM

0

Yes according to my reading of the doc, if the case-like key matches, the rest of the list is implicitly assumed to match the destructuring-lambda-list.

Jim Newton

5/24/2016 3:39:00 PM

0

Yes according to my reading of the doc, if the case-like key matches, the rest of the list is implicitly assumed to match the destructuring-lambda-list.

Kaz Kylheku

5/24/2016 3:42:00 PM

0

On 2016-05-24, Grumpus <grumpus@example.org> wrote:
> Kaz Kylheku wrote:
>
>> And it appears to reduce to the simple non-key case if you use a
>> fixed key, and use only that key in all the cases.
>
> If that's how destructuring-case *really* works, the docs aren't any
> good:
>
> The clause whose case-keys matches car of key, as if by case, ccase,
> or ecase, is selected, and FORMs are then executed with cdr of key
> is destructured and bound by the destructuring-lambda-list.

Hmm. I.e. when the routing takes place on the key, then exactly one
destructuring pattern is eligible, and must match the datum.

Thus it is not selection over destructuring cases at all.

Rather, indeed, it is nothing more than a syntactic sugar which
condenses the following pattern:

(ecase (car obj)
(<key1> (destructuring-bind <pattern1> (cdr obj)
code1 ...))
(<key2> (destructuring-bind <pattern2> (cdr obj)
code2 ...))
...
(<keyN> (destructuring-bind <patternN> (cdr obj)
codeN ...))

Except (one would hope) that obj is evaluated only once.

Someone was writing lots of code like the above and decided to
factor out the repetition of destructive-bind and related noise;
certainly a worthwhile macro. The name is just badly chosen; I'd call
the above case-bind or something.

Kaz Kylheku

5/25/2016 5:42:00 PM

0

On 2016-05-24, Jim Newton <jimka.issy@gmail.com> wrote:
> Does it use the types of the arguments in its decision of which clause to branch to?
> Or does it rely only on the structure?
>
>> TXR Lisp tree-case:
>>
>> http://www.nongnu.org/txr/txr-manpage.html#...
>>
>
> The cool thing, in my opinion, about this implementation is that it reads the type declarations and uses that in the decision making.
>
> E.g.,
> (destructuring-bind DATA
> ((a (b c))
> (declare (type fixnum a b) (type string c))
> ...)

There is something that bothers me in a design which dispatches on the
contents of (declare ...)

It's just not done. Declarations are supposed to be optional, so that if
we remove them, the code means the same thing.

Why not design the object system that way too?

(defmethod foo (a b)
(declare ((type aclass a) (type bclass b)))
...)

You know? It's noisy and it "hijacks" declarations.

Anyway for pattern matching, we have existing libs like:

fare-matcher: http://cliki.net/fa...

.... which is declared by its own author to be obsolete w.r.t:

optima: https://github.com/m2...