unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* new function proposal alist-to-hash
@ 2019-10-03 21:25 Andrea Corallo
  2019-10-03 21:40 ` Drew Adams
  2019-10-03 21:56 ` Stefan Monnier
  0 siblings, 2 replies; 9+ messages in thread
From: Andrea Corallo @ 2019-10-03 21:25 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 303 bytes --]

Hi all,
I'd like to propose a new simple function called alist-to-hash to make
hash-tables from a-lists.
In case something equivalent already exists I apologize.
Please be patient, first contribution here :)

I attach the patch.

Best Regards
  Andrea

PS Copyright paperwork are done.
-- 
akrl@sdf.org

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-new-function-to-make-hash-tables-from-a-lists.patch --]
[-- Type: text/x-patch, Size: 1730 bytes --]

From e2bca29d6fca8c1a40e57526432cb4ce29b2245b Mon Sep 17 00:00:00 2001
From: Andrea Corallo <akrl@sdf.org>
Date: Thu, 3 Oct 2019 22:56:43 +0200
Subject: [PATCH] Add new function to make hash-tables from a-lists

* lisp/emacs-lisp/subr-x.el (alist-to-hash):
  New function make hash-tables from a-lists.
* etc/NEWS: Announce it.
---
 etc/NEWS                  |  3 +++
 lisp/emacs-lisp/subr-x.el | 12 ++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index c8cc753..f4924ba 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -24,6 +24,9 @@ applies, and please also update docstrings as needed.
 \f
 * Installation Changes in Emacs 27.1

+** New function 'alist-to-hash'.
+Create recursively hash-tables from a-lists.
+
 ** Emacs now uses GMP, the GNU Multiple Precision library.
 By default, if 'configure' does not find a suitable libgmp, it
 arranges for the included mini-gmp library to be built and used.
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 3da5241..e67f59b 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -204,6 +204,18 @@ hash-table-values
   "Return a list of values in HASH-TABLE."
   (cl-loop for v being the hash-values of hash-table collect v))

+(defun alist-to-hash (a-list &rest keyword-args)
+  "Create recursively an hash table from A-LIST.
+KEYWORD-ARGS parameters are forwarded to `make-hash-table'."
+  (cl-loop with h = (apply #'make-hash-table keyword-args)
+	   for (k . v) in a-list
+	   do (puthash k
+		       (if (consp v)
+			   (apply #'alist-to-hash v keyword-args)
+			 v)
+		       h)
+	   finally (return h)))
+
 (defsubst string-empty-p (string)
   "Check whether STRING is empty."
   (string= string ""))
--
2.7.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* RE: new function proposal alist-to-hash
  2019-10-03 21:25 new function proposal alist-to-hash Andrea Corallo
@ 2019-10-03 21:40 ` Drew Adams
  2019-10-03 21:56 ` Stefan Monnier
  1 sibling, 0 replies; 9+ messages in thread
From: Drew Adams @ 2019-10-03 21:40 UTC (permalink / raw)
  To: Andrea Corallo, emacs-devel

> I'd like to propose a new simple function called alist-to-hash to make
> hash-tables from a-lists.
> In case something equivalent already exists I apologize.

(Sort of the inverse of
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=28753)



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: new function proposal alist-to-hash
  2019-10-03 21:25 new function proposal alist-to-hash Andrea Corallo
  2019-10-03 21:40 ` Drew Adams
@ 2019-10-03 21:56 ` Stefan Monnier
  2019-10-03 22:07   ` Andrea Corallo
  1 sibling, 1 reply; 9+ messages in thread
From: Stefan Monnier @ 2019-10-03 21:56 UTC (permalink / raw)
  To: Andrea Corallo; +Cc: emacs-devel

> I'd like to propose a new simple function called alist-to-hash to make
> hash-tables from a-lists.

I think `map-into` does that:

    (map-into '((a . 1) (b . 2)) 'hash-table)
    

-- Stefan




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: new function proposal alist-to-hash
  2019-10-03 21:56 ` Stefan Monnier
@ 2019-10-03 22:07   ` Andrea Corallo
  0 siblings, 0 replies; 9+ messages in thread
From: Andrea Corallo @ 2019-10-03 22:07 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> I'd like to propose a new simple function called alist-to-hash to make
>> hash-tables from a-lists.
>
> I think `map-into` does that:
>
>     (map-into '((a . 1) (b . 2)) 'hash-table)
>     
>
> -- Stefan

Cool good to know!
The only thing is that this is not recursive.
I think having it recursive make the use quite lighter in cases with
nesting.

Bests
  Andrea

-- 
akrl@sdf.org



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: new function proposal alist-to-hash
@ 2019-10-04  9:58 Andrea Corallo
  2019-10-04 19:16 ` Stefan Monnier
  0 siblings, 1 reply; 9+ messages in thread
From: Andrea Corallo @ 2019-10-04  9:58 UTC (permalink / raw)
  To: akrl; +Cc: Stefan Monnier, emacs-devel

I just wanted elaborate a little more on the following two points:

- I think is quite useful to be able to create in a concise and
  explicit way nested hash tables. This is a common feature of many
  "modern" languages.
  Here both solutions compared:

(alist-to-hash '((a . x)
		 (b . ((i . j)
		       (k . l)))
		 (c . y)))

(map-into `((a . x)
	    (b . ,(map-into '((i . j)
			      (k . l))
			    'hash-table))
	    (c . y))
	  'hash-table)

- map-into does not let you tweak make-hash-table parameters.
  This is especially a limitation regarding :test so is effectively a
  solution to say ~50% of the use cases.

Bests
  Andrea

--
akrl@sdf.org



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: new function proposal alist-to-hash
  2019-10-04  9:58 Andrea Corallo
@ 2019-10-04 19:16 ` Stefan Monnier
  2019-10-05  8:18   ` Andrea Corallo
  0 siblings, 1 reply; 9+ messages in thread
From: Stefan Monnier @ 2019-10-04 19:16 UTC (permalink / raw)
  To: Andrea Corallo; +Cc: emacs-devel

> - I think is quite useful to be able to create in a concise and
>   explicit way nested hash tables. This is a common feature of many
>   "modern" languages.
>   Here both solutions compared:
>
> (alist-to-hash '((a . x)
> 		 (b . ((i . j)
> 		       (k . l)))
> 		 (c . y)))
>
> (map-into `((a . x)
> 	    (b . ,(map-into '((i . j)
> 			      (k . l))
> 			    'hash-table))
> 	    (c . y))
> 	  'hash-table)

Not sure I understand: if you only use it for immediate/literal data,
then I guess you could just use the #s(hash-table data (...)) syntax.
And for non-literal maps, this needs to somehow distinguish values that
are alists from others, like

    (map-into (mapcar (lambda (x)
                        (if (and (consp (cdr x)) (consp (cadr x)))
                            (cons (car x) (map-into (cdr x) 'hash-table))
                          x))
                      my-alist)
              'hash-table)

But I suspect that this is not frequently needed.
[ BTW, the above code is screaming for something like `map-values-apply`
  but which returns a *map* rather than a list.  ]

And if you really need this to apply recursively, it basically means
you don't have a map but a *tree* where each node is originally
implemented as an alist and which you want to transform into the same
tree where each node is now a hash-table.  Again, this is likely not
needed very frequently (and I suspect that each time it's needed, it
will have slightly different needs/constraints).

> - map-into does not let you tweak make-hash-table parameters.
>   This is especially a limitation regarding :test so is effectively a
>   solution to say ~50% of the use cases.

Yes, this is a very serious limitation of `map-into`.
I decided not to try to tackle it when I converted map.el to use
cl-defmethod, but I'd welcome help on this.


        Stefan




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: new function proposal alist-to-hash
  2019-10-04 19:16 ` Stefan Monnier
@ 2019-10-05  8:18   ` Andrea Corallo
  2019-10-05 15:13     ` Stefan Monnier
  0 siblings, 1 reply; 9+ messages in thread
From: Andrea Corallo @ 2019-10-05  8:18 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> - I think is quite useful to be able to create in a concise and
>>   explicit way nested hash tables. This is a common feature of many
>>   "modern" languages.
>>   Here both solutions compared:
>>
>> (alist-to-hash '((a . x)
>> 		 (b . ((i . j)
>> 		       (k . l)))
>> 		 (c . y)))
>>
>> (map-into `((a . x)
>> 	    (b . ,(map-into '((i . j)
>> 			      (k . l))
>> 			    'hash-table))
>> 	    (c . y))
>> 	  'hash-table)
>
> Not sure I understand: if you only use it for immediate/literal data,
> then I guess you could just use the #s(hash-table data (...)) syntax.

Sure, my example was just to point out easiness of use from a syntactic
point of view. The good of having the list quoted by the user is that
he can quasi-quote when needed what he needs.

> And for non-literal maps, this needs to somehow distinguish values that
> are alists from others, like
>
>     (map-into (mapcar (lambda (x)
>                         (if (and (consp (cdr x)) (consp (cadr x)))
>                             (cons (car x) (map-into (cdr x) 'hash-table))
>                           x))
>                       my-alist)
>               'hash-table)
>
> But I suspect that this is not frequently needed.
> [ BTW, the above code is screaming for something like `map-values-apply`
>   but which returns a *map* rather than a list.  ]
>
> And if you really need this to apply recursively, it basically means
> you don't have a map but a *tree* where each node is originally
> implemented as an alist and which you want to transform into the same
> tree where each node is now a hash-table.  Again, this is likely not
> needed very frequently (and I suspect that each time it's needed, it
> will have slightly different needs/constraints).

I've maybe used not the correct nomenclature sorry.
What I want to say is that being an hash table a key value map it maps
1:1 into alist.
That said I think is quite important to be able to express in a clear
and short way nested hashes.
In python it would be simply something like this:

nested_dict = { 'dictA': {'key_1': 'value_1'},
                'dictB': {'key_2': 'value_2'}}

Note that here just litteral are used but also variables can be
evaluated while creating the dictionaries.

A tree of a-list for the reason I've expressed above would be to me the
most natural way to express the same.  Given that a recursive
implementation that walks this tree like the one in patch I've posted
can do the job.

Maybe I'm the only that see a value on that but I think is useful :)

>> - map-into does not let you tweak make-hash-table parameters.
>>   This is especially a limitation regarding :test so is effectively a
>>   solution to say ~50% of the use cases.
>
> Yes, this is a very serious limitation of `map-into`.
> I decided not to try to tackle it when I converted map.el to use
> cl-defmethod, but I'd welcome help on this.
>
>
>         Stefan

Ok I'm looking into it.

Bests
  Andrea

-- 
akrl@sdf.org



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: new function proposal alist-to-hash
  2019-10-05  8:18   ` Andrea Corallo
@ 2019-10-05 15:13     ` Stefan Monnier
  2019-10-05 15:45       ` Andrea Corallo
  0 siblings, 1 reply; 9+ messages in thread
From: Stefan Monnier @ 2019-10-05 15:13 UTC (permalink / raw)
  To: Andrea Corallo; +Cc: emacs-devel

> Sure, my example was just to point out easiness of use from a syntactic
> point of view. The good of having the list quoted by the user is that
> he can quasi-quote when needed what he needs.

But reading the rest of your response, it seems you're mostly interested
in the "literal" case (maybe using backquote+unquote to evaluate some
sub-elements).

> In python it would be simply something like this:
>
> nested_dict = { 'dictA': {'key_1': 'value_1'},
>                 'dictB': {'key_2': 'value_2'}}

Python uses hash-tables to represent objects, whereas in Elisp this is
not the case: we use cl-defstruct, alist, or plists instead (hash-tables
are considered as relatively expensive, so if you know there will only
be a small number of entries, you're often better off with an alist).

Nested hash-tables are very rare in Elisp (so far).


        Stefan




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: new function proposal alist-to-hash
  2019-10-05 15:13     ` Stefan Monnier
@ 2019-10-05 15:45       ` Andrea Corallo
  0 siblings, 0 replies; 9+ messages in thread
From: Andrea Corallo @ 2019-10-05 15:45 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Sure, my example was just to point out easiness of use from a syntactic
>> point of view. The good of having the list quoted by the user is that
>> he can quasi-quote when needed what he needs.
>
> But reading the rest of your response, it seems you're mostly interested
> in the "literal" case (maybe using backquote+unquote to evaluate some
> sub-elements).

Correct.

>> In python it would be simply something like this:
>>
>> nested_dict = { 'dictA': {'key_1': 'value_1'},
>>                 'dictB': {'key_2': 'value_2'}}
>
> Python uses hash-tables to represent objects, whereas in Elisp this is
> not the case: we use cl-defstruct, alist, or plists instead (hash-tables
> are considered as relatively expensive, so if you know there will only
> be a small number of entries, you're often better off with an alist).
>
> Nested hash-tables are very rare in Elisp (so far).

I guess one of the reasons is that as discussed depending on the case
expressing them in a literal form can be not so convenient.

>         Stefan
>

Bests
  Andrea

--
akrl@sdf.org



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-10-05 15:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-10-03 21:25 new function proposal alist-to-hash Andrea Corallo
2019-10-03 21:40 ` Drew Adams
2019-10-03 21:56 ` Stefan Monnier
2019-10-03 22:07   ` Andrea Corallo
  -- strict thread matches above, loose matches on Subject: below --
2019-10-04  9:58 Andrea Corallo
2019-10-04 19:16 ` Stefan Monnier
2019-10-05  8:18   ` Andrea Corallo
2019-10-05 15:13     ` Stefan Monnier
2019-10-05 15:45       ` Andrea Corallo

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).