Re: Some thoughts on dicts in SWIPL 7
Carlo Capelli <[email protected]>
| Newsgroups | gmane.comp.ai.prolog.swi |
|---|---|
| Message-ID | <CABty9wxa_aY9n48SA0SofMOHSFup55Jg63s7z5_H9JWwSdej0g@mail.gmail.com> |
2014-02-18 11:17 GMT+01:00 Carlo Capelli <[email protected]>: > I also like dicts syntax, just missing semantic highlighting for the keys > when used in functional notation. > Given the small visual difference between dots and commas, porting > cluttered code can result in difficult to spot errors. > > Is a patch to library(prolog_colour) underway ? Otherwise, I could try to > do... > > TIA Carlo > > I forgot: a pattern that could be handy could be a member_dict/2, to avoid this kind of code (member(F, T.foreignKeys), F >:< _{pkCol:PkCol, fkTable:FkTable, fkCol:FkCol}) > > 2014-02-18 9:45 GMT+01:00 Jan Wielemaker <[email protected]>: > > Hi Bob, >> >> Thanks for sharing. I've been using dicts during the last couple of days >> for real programming too. To be precise, for implementing the completely >> imperative description of processing RDFa documents. The good news is >> that >> it allows for an almost literal translation of the text. It looks quite >> ok, but from a Prolog point it is a bit awkward :-( Still, having an >> implementation that stays close to the spec is probably better than >> trying a declarative redesign of the spec and implementing that ... >> >> On 02/17/2014 10:39 PM, Bob Minors wrote: >> > As a learning exercise, I've been converting an existing program to use >> > dicts in place of some rather clumsy ordered list structures. It's going >> > quite well - I like dicts - and it's given rise to some thoughts that >> > I'd like to share. Two little things and a broad question about >> > programming style. >> > >> > The original data structure was an ordered list of 27 elements (some of >> > which were themselves ordered lists) and, when calling predicates on it, >> > I would pick out the ones I wanted using nth0. Something like this: >> > >> > foo(X,Y) :- nth0(12,X,Apples), nth0(23,X,Bananas), >> > foo1(Apples,Bananas,Y). >> > >> > This worked fine, but it's always been ugly and tricky to maintain. Now >> > I've replaced the whole X structure with a dict and I can do something >> > like this: >> > >> > foo(X,Y) :- foo(X.apples,X.bananas,Y). >> > >> > which is simpler, more readable and more maintainable. That's the >> > motivation. >> >> That was the idea. Note that a fixed length of 27 elements was a rather >> poor design. Using a compound and arg/3 or library(record) would have >> been a better choice. But still, with dicts it is barely slower than >> arg/3 and more readable. Good :-) One of the aims of dicts was also >> to make the choice easier. That seems to have worked too in your case. >> >> > One thing I needed to do in several places, was to create empty dicts >> > with given tags and given lists of keys but with all the values >> > uninstantiated, ready for filling in later. There's no built-in function >> > that does quite what I wanted, so this was how I coded it: >> > >> > free_pair(X,X:_). >> > >> > blank_dict(Tag,Keylist,Dict) :- >> > maplist(free_pair,Keylist,Pairs), >> > dict_create(Dict,Tag,Pairs). >> > >> > 12 ?- blank_dict(foo,[a,b,c],Dict). >> > Dict = foo{a:_G1029, b:_G1035, c:_G1041}. >> > >> > It's not a huge thing, it's used in just seven places in my program but >> > it saves typing ":_" over and over again (in one case, 27 times). Is >> > this something that would often be done with dicts? Would it be worth >> > having a built-in function for it? Just a suggestion. >> >> I don't know. Is there so much advantage in >> >> ?- blank_dict(foo,[a,b,c],Dict). >> vs. ?- Dict = foo{a:_,b:_,c:_}. >> >> The latter is definitely faster (unless we do partial evaluation). The >> still open future route is to have psi-terms, so you can extend the term >> dynamically using unification. Why don't you start with a small dict and >> use .put(Name,Value)? Of course, this creates a new dict, so you need >> some >> form of threaded state. >> >> > Next thing: one of the values in the top-level dict is a list of smaller >> > dicts, representing a FIFO queue of elements waiting to be processed, >> > and there is a predicate that needs to check one of the key values in >> > the dict at the head of the list to see if it's ready for processing. >> > I've defined a function that plucks out head of the list: >> > >> > X.head(Tag) := H :- X.Tag=[H|_]. >> > >> > so I can write something like this: >> > >> > process_queue(X) :- X.head(queue).is_ready(), >> process_queue1(X.queue). >> > >> > where the is_ready() is defined elsewhere as a function on a queue >> > element dict. This works and is easy to read (for me, at least) but it's >> > looking more like functional programming than conventional Prolog and >> > I'm starting to feel the ground shifting under my feet. Is this a bad >> > thing? Probably not. >> >> All in all, this is still mapped to traditional Prolog, i.e., it is >> only syntactic sugar. Variables are still logical variables and code >> can still be non-deterministic. We'll have to learn good practice >> (thanks for sharing). This seems fine to me. >> >> > Now a stylistic question. When writing predicates that call smaller >> > predicates, there is a choice between of pulling out the relevant fields >> > from the dict at the top level and passing them down as variables to the >> > lower-level predicates, or simply passing down the whole dict and >> > letting the lower-level predicates take what they want. One the one >> > hand, something like >> > >> > foobar(X,FooBar) :- foo(X.a, X.b, Foo), bar(X.c, X.d, X.e, Foo, >> Foobar). >> > >> > or this: >> > >> > foobar(X,Y) :- foo(X,Foo), bar(X,Foo,FooBar). >> > >> > The first scheme keeps all the structural detail of X at the top level >> > and the lower level predicates (foo and bar) don't need to know about >> > it, so if I change the top-level structure they should be unaffected and >> > that seems good from a module point of view; but the second scheme might >> > be more maintainable if, say, foo is later improved and needs to >> > reference X.d after all - this can be done without changing the >> > top-level calling predicates, which makes the top level more robust. >> > Having thought about it, I've come to the conclusion that it depends on >> > which is expected to be the more stable and which the more volatile >> > during program development - top-level dict or lower-level modules. >> > Top-down design vs bottom-up coding. No right answer. >> >> I think that your observation is correct. There is no uniform answer. >> I have similar issues with using option lists. The tradeof appears in >> any language having record-like data types. >> >> Cheers --- Jan >> _______________________________________________ >> SWI-Prolog mailing list >> [email protected] >> https://lists.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog >> > > -------------- next part -------------- HTML attachment scrubbed and removed