* 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).