List comprehension for C++ OpenCog!!!

102 views
Skip to first unread message

Nil Geisweiller

unread,
May 15, 2013, 7:35:44 AM5/15/13
to OpenCog
Hi,

for those who don't get email notifications from github, I've finally pulled it off, supporting both STL functors and C++11 lambda! :-)

I know that boost.range offers something almost as good BUT NOT as good/compact (see below). And yeah it's not standard but it's better than nothing, once C++ has it (and it will) then we can replace the code using that cooked comprehension by the standard.

Also, there is no filtering yet (I'll add it as soon as I need it), and boost.pheonix is not supported but I don't think that would bother anyone.

Here's an example

#include <opencog/comprehension.h>
using namespace opencog;

std
::vector<int> ivec = {1,2,3,4}; auto ovec = vector_comp(ivec, [](int x) { return (float)x + 1; });
// ovec == {2.0,3.0,4.0,5.0}

Did you see? The return type of the function defines the vector value_type!!!

Nil

Nil Geisweiller

unread,
May 15, 2013, 7:38:20 AM5/15/13
to OpenCog
I forgot to tell, list and set are supported as well ofc, in that case you use

list_comp or set_comp

And it doesn't matter the container type of the input, the container type if defined by the comprehension type (the prefix in *_comp).

Nil

Nil Geisweiller

unread,
May 15, 2013, 8:18:46 AM5/15/13
to OpenCog
Turns out I needed a filter now so, here it is! Now you can do

#include <opencog/util/comprehension.h>
using namespace opencog;

std
::vector<int> ivec = {1,2,3,4}; auto ovec = vector_comp(ivec, [](int x) { return (float)x + 1; }, [](int x) { return x%2; });
// ovec == {2.0,4.0}

Nil

Matt Chapman

unread,
May 15, 2013, 12:51:51 PM5/15/13
to opencog
Very cool!

Why not put this in GitHub as a standalone library? It seems very desirable for all kinds of projects, not just opencog.

All the Best,

Matt Chapman
Ninjitsu Web Development
http://www.NinjitsuWeb.com
ph: 818-660-6465 (818-660-NINJA)
fx: 888-702-3095

http://www.linkedin.com/profile/view?id=13333058

If you want to endorse my skills on Linked In, the most valuable endorsements to me are "Open Source" and "Software Development."

--
The contents of this message should be assumed to be Confidential, and may not be disclosed without permission of the sender.


--
You received this message because you are subscribed to the Google Groups "opencog" group.
To unsubscribe from this group and stop receiving emails from it, send an email to opencog+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.
Visit this group at http://groups.google.com/group/opencog?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Linas Vepstas

unread,
May 15, 2013, 1:38:03 PM5/15/13
to opencog
Can I ask for a name change, from vector_comp to map_vector/map_set/map_list ?

This is to closer to the industry-standard naming convention for these functions; so for example, srfi-1 provides a details description of what they are and how they work for lisp, and it seemed like both CaML and Haskell use names that are very nearly identical to those used in srfi-1.


so for example, the above describes:

map proc clist1 clist2 ... -> list
proc is a procedure taking as many arguments as there are list arguments and returning a single value. map applies proc element-wise to the elements of the lists and returns a list of the results, in order. 

Thus, in C++, it should be called map_vector, map_set, etc. (why not map<typename> where typename is a container?)

for-each proc clist1 clist2 ... -> unspecified
The arguments to for-each are like the arguments to map, but for-each calls proc for its side effects rather than for its values. Unlike map, for-each is guaranteed to call proc on the elements of the lists in order from the first element(s) to the last, and the value returned by for-each is unspecified.

Well, In C++, we already have something called for_each which is similar, not the same.

What you are now describing is this:

filter-map f clist1 clist2 ... -> list
Like map, but only true values are saved.

The below could be useful, I imagine.

filter pred list -> list
Return all the elements of list that satisfy predicate pred. The list is not disordered -- elements that appear in the result list occur in the same order as they occur in the argument list.


srfi-1 is filled with handy-dandy utilities, that, if implemented in C++, could be just as useful there, too.

--linas


Linas Vepstas

unread,
May 15, 2013, 1:41:30 PM5/15/13
to opencog
Hi Matt,

On 15 May 2013 11:51, Matt Chapman <ma...@ninjitsuweb.com> wrote:
Very cool!

Why not put this in GitHub as a standalone library? It seems very desirable for all kinds of projects, not just opencog.


We've talked about moving the contents of opencog/util to a stand-alone git repo.  Doing this would make it easier to compartmentalize/modularize other parts of opencog as well (so I'm for it). However, doing so hasn't seemed very urgent ... and, if done wrong/sloppily, it just adds complexity to an already complex build process.

--linas 

Nil Geisweiller

unread,
May 15, 2013, 6:01:38 PM5/15/13
to OpenCog
On Wed, May 15, 2013 at 7:51 PM, Matt Chapman <ma...@ninjitsuweb.com> wrote:
Very cool!

Why not put this in GitHub as a standalone library? It seems very desirable for all kinds of projects, not just opencog.

Good idea, this made me obviously search for list comprehension implementations in C++ in github and I found a few projects not listed in Wikipedia!

All were either too limited or apparently abandoned except for one

https://github.com/pfultz2/Linq

really cool stuff, this makes me think we may not need my hacking after all (although it's still a tiny bit more compact, and would avoid an extra dependency). I'm not sure...

Nil

Nil Geisweiller

unread,
May 15, 2013, 6:09:44 PM5/15/13
to OpenCog
On Wed, May 15, 2013 at 8:38 PM, Linas Vepstas <linasv...@gmail.com> wrote:
Can I ask for a name change, from vector_comp to map_vector/map_set/map_list ?

This is to closer to the industry-standard naming convention for these functions; so for example, srfi-1 provides a details description of what they are and how they work for lisp, and it seemed like both CaML and Haskell use names that are very nearly identical to those used in srfi-1.


so for example, the above describes:

map proc clist1 clist2 ... -> list
proc is a procedure taking as many arguments as there are list arguments and returning a single value. map applies proc element-wise to the elements of the lists and returns a list of the results, in order. 

Thus, in C++, it should be called map_vector, map_set, etc. (why not map<typename> where typename is a container?)

+1 for map<typename>, ofc!!!!
 

for-each proc clist1 clist2 ... -> unspecified
The arguments to for-each are like the arguments to map, but for-each calls proc for its side effects rather than for its values. Unlike map, for-each is guaranteed to call proc on the elements of the lists in order from the first element(s) to the last, and the value returned by for-each is unspecified.

Well, In C++, we already have something called for_each which is similar, not the same.

What you are now describing is this:

filter-map f clist1 clist2 ... -> list
Like map, but only true values are saved.

The below could be useful, I imagine.

filter pred list -> list
Return all the elements of list that satisfy predicate pred. The list is not disordered -- elements that appear in the result list occur in the same order as they occur in the argument list.

mapfilter<typename> is OK as far as I'm concerned.

But again as I said I've found

https://github.com/pfultz2/Linq

which makes me unsure we need my hacking...

Although there something about linq is that it duplicates a lot of STL or boost functionalities without gaining in compactness for most of it, which might not be desirable (it's better to stick with one way of expressing stuff).

I'm confused about what to use at that point.

Nil

Linas Vepstas

unread,
May 15, 2013, 9:26:27 PM5/15/13
to opencog
On 15 May 2013 17:09, Nil Geisweiller <ngei...@googlemail.com> wrote:

But again as I said I've found

https://github.com/pfultz2/Linq

which makes me unsure we need my hacking...

Well, Linq is designed to look as much as possible like SQL.  It seems to implement more or less standard, basic SQL, except that the parens and commas are weirdly placed.  Before you use it, you have to ask yourself "do I want to write code as if I was programming in SQL?"  and I think the answer, for what we do, is mostly "no". 
 
I'm confused about what to use at that point.

Do what you are currently doing.  It avoids adding (yet another) dependency that people will trip over.  For opencog, a reasonable rule-of-thumb might be: if we can do it ourselves in under 500 or 1KLOC, then we should.  If we could remove 2KLOC or 4KLOC of our own custom code by using someone else's library, then we should.  I think you are well under 500 LOC.

KISS keep it simple, stupid.

--linas

Nil Geisweiller

unread,
May 16, 2013, 12:30:32 AM5/16/13
to OpenCog
Thanks!!! I like that answer. So I'll stick with my custom comprehension/filtermap, I think eventually boost.range is gonna add something like that anyway so we can just wait till that come.

Nil
 

--linas

Nil Geisweiller

unread,
May 16, 2013, 12:43:21 AM5/16/13
to OpenCog
On Thu, May 16, 2013 at 1:09 AM, Nil Geisweiller <ngei...@googlemail.com> wrote:



On Wed, May 15, 2013 at 8:38 PM, Linas Vepstas <linasv...@gmail.com> wrote:
Can I ask for a name change, from vector_comp to map_vector/map_set/map_list ?

This is to closer to the industry-standard naming convention for these functions; so for example, srfi-1 provides a details description of what they are and how they work for lisp, and it seemed like both CaML and Haskell use names that are very nearly identical to those used in srfi-1.


so for example, the above describes:

map proc clist1 clist2 ... -> list
proc is a procedure taking as many arguments as there are list arguments and returning a single value. map applies proc element-wise to the elements of the lists and returns a list of the results, in order. 

Thus, in C++, it should be called map_vector, map_set, etc. (why not map<typename> where typename is a container?)

+1 for map<typename>, ofc!!!!

oh, I can't do that actually, I can't provide a template without it's value_type! Like say

comp<std::vector>

can't do.

So I'm just gonna stick with with my current notation... {vector,list,set}_comp.

Nil
Reply all
Reply to author
Forward
0 new messages