
Logic Programming (Prolog, ASP, etc) and GRAKN.AI (a distributed knowledge base) - graqlbot
https://blog.grakn.ai/isa-graql-logic-program-8af1258054a4
======
Karrot_Kream
Small nit:

> If the application requires constant knowledge updates, having a database is
> much better than revising and reloading a Prolog program.

Most modern Prologs support the ability to assert and retract facts, so you
basically get an in-memory DB to run clauses against continuously.

Other than that, really cool stuff! Love to see logic programming applied in
new and interesting ways.

~~~
dmix
I'm curious if they should have built on top of JMAP by Fastmail:
[https://blog.fastmail.com/2014/12/23/jmap-a-better-way-to-
em...](https://blog.fastmail.com/2014/12/23/jmap-a-better-way-to-email/)

It's possible this was far too close to the original email protocol to make
sense though.

------
6d6b73
This is why we can't have nice things:

“Find all the people who are named ‘Titus’”

<pre> In Graql:

match $x isa person, has firstname $y; $y val is “Titus”;

In ASP:

match(Person) :- isa(Person, person), has(Person, firstname, "Titus"). #show
match/1\. </pre>

Why can't it simply be "FIND people NAME 'Titus' " ?

~~~
DonbunEf7
I am neither Byrd nor Friedman but I will try my best.

The short answer is that it doesn't compose very well, especially when doing
relational programming.

Let's say that `people` is a record of some sort, and not a relation. That is,
when we extract people, we get records of data which we can manipulate, and
not a set of functions which let us relate the records to each other. Now,
imagine a logical query which has the following steps:

    
    
        exists p :Person
        guard p.name == "Titus"
        exists gp :Person ? isGrandParent(gp, p)
        call scan(gp)
        return gp, p
    

How is this actually going to be executed? Well, you can imagine that first,
we'll fetch a Person record, then we'll check if the name is "Titus", and then
we'll fetch his grandparents, calling `scan` on each one. (No, I don't know
why we would scan grandparents. Here in the USA, we actually let them skip the
scanners.) Seems easy, right? What if we make a tiny swap...

    
    
        exists p :Person
        exists gp :Person ? isGrandParent(gp, p)
        call scan(gp)
        guard p.name == "Titus"
        return gp, p
    

Crap, this isn't the same program. We'll scan every grandparent, even ones
without grandkids named Titus.

Relational operators are supposed to commute, but these ones don't commute!
What happened? Well, accessing a runtime-computed non-relational fact, like
the name of a person here, is an impure operation. It doesn't compose.

So! What's the right answer? We have to express the person<->name connection
as a relation rather than a record:

    
    
        exists p :Person ? personHasName(p, "Titus")
        exists gp :Person ? isGrandParent(gp, p)
        call somePred(gp)
        return gp, p
    

Byrd's thesis glosses over this point and simply says that we should already
have internalized the impurity of `project` or other projection operators.

Edit: I fixed some typos. Also, this paper [0] on my paperstack has Friedman
as a co-author and purports to solve this problem in a generic way by adding
pure symbolic constraints to miniKanren.

[0]
[https://arxiv.org/pdf/1701.00633.pdf](https://arxiv.org/pdf/1701.00633.pdf)

~~~
NotAUsername
Great point about compositionality, thank you!

------
eggy
My wife is Indonesian and has only one name, her give name or first name. No
surname. How do you address that in the example? A modifier of sorts?

~~~
NotAUsername
Good point. The declaration is just an extra constraint. It specifies what you
can insert not what you have to insert. So in your example you can just insert
some of the resources.

~~~
eggy
Thanks. I didn't realize it wasn't strict about empty fields. More like a form
with lots of fields.

