I've put an introductory Prolog tut for SQL programmers on Swish

I worked at Google, and I have to disagree with some of that. (I have no opinion on Facebook’s GraphQL, as I haven’t used it). Considering when they were built, Bigtable, Mapreduce, Borg are pretty awesome pieces of technology (and I presume their OO descendants such as HBase, Hadoop, Kubernetes are also impressive).
[There are some aspects of Bitable, Mapreduce, Borg that I dislike intensely; but if I had designed them, I’d merely have made a different set of mistakes.]

I recently had to sort out a pig’s breakfast of mistakes in my retirement funds (it seems that in this modern age, funds are transferred between institutions by hand, and nobody proof-reads the results); I ended up writing multiple DCGs to parse reports from about 4 companies, transformed the resulting data into Prolog predicates, and then ran some validation checks that would have driven me crazy if I’d used SQL. I’ve been thinking of writing up this experience, but it’d be quite a bit of work to remove the personal stuff and also to make it interesting to anyone but me.

My comment is admittedly extremely facetious. My frustration with Facebook’s GraphQL mainly came about from writing scripts to read data Facebook initially freely provided to create a gig guide website for my home town. At the the time, I was shocked at the amount of data Facebook allowed anyone to harvest (this was before the Cambridge Analytica scandal).

Subsequent to that, Facebook went on the other end of the spectrum: cutting back on what could be obtained to the point where stuff people wanted disseminated – as in punk bands on what pub they were playing when, could no longer be accessed.

My main gripe against GraphQL and other corporate hype software is that if you go to https://graphql.org/, it’s all marketing pufferry. Lots of hype, no clear information on what it does or how to use it.

This is becoming a nice tutorial! Looking at the Delete section, we can do a little better than

:- findall(student(SID, SName, GPA, SizeHS),
        (student(SID, SName, GPA, SizeHS),
         aggregate_all(count, Major, apply(SID, _, Major, _), Count),
         Count > 2), Students),
    forall(member(student(SID, SName, GPA, SizeHS), Students), 
           retract(student(SID, SName, GPA, SizeHS))).

There is no reason to create a list. You can simply do

?- forall(( student(SID, SName, GPA, SizeHS),
            aggregate_all(count, Major, apply(SID, _, Major, _), Count),
            Count > 2),
          retract(student(SID, SName, GPA, SizeHS))).

It is safe to assert/retract to/from a dynamic predicate from which you are enumerating solutions. Conforming the ISO required logical update view, the set of solutions generated on backtracking is not affected by clauses that are added or deleted during the enumeration.

P.s. Why do you put the last queries in a program as directives instead of using a query?

Thanks @jan. I’ll update. I’ve just completed Part 3 which does the examples on graph traversal.

Here Prolog really shines. I find the with recursive... SQL code unreadable, whereas doing these in Prolog is really simple.

If I understand you’re question your asking why I first create a program block eg

:- forall((    friend(ID1, ID2), 
               likes(ID1, ID2), 
               \+likes(ID2, ID1)    
          ), retract(likes(ID1, ID2))).

and then a query

highschooler(_A, Name1, Grade1),
highschooler(_B, Name2, Grade2),
likes(_A, _B).

The reason is the Stanford MooC checker expects the database to be back in the original state each problem, and I’ve discovered that with Swish if I modify the data in a query, it remains changed for future queries.

I’ve found the modifications in the program block only apply to the following query assuming I haven’t set the global icon, which is very handy in this case.

I see. For your understanding, nothing is preserved in sandboxed SWISH. For each query the relevant source is transferred to the server, compiled in an isolated module, the query is executed in a thread and both the module and the executing thread are destroyed.

So, your directive is simply re-executed for each query resulting in the same state.

It turns out the reason I was getting different results was from using the same variable names, which wasn’t a problem when the forall… were written as separate :- … stanzas. I’ve updated the examples to get rid of the program blocks.