Negation troubles: candidate-received-no-votes

121 views
Skip to first unread message

Gordon Gustafson

unread,
Dec 23, 2016, 11:40:18 PM12/23/16
to minikanren
Here's my attempt at implementing an example of a "does not exist" relation in core.logic:

(
ns diplomacy.vote
 
(:refer-clojure :exclude [==])
 
(:use [clojure.core.logic])
 
(:require [clojure.core.logic.pldb :as pldb]))

;; `voter-name` voted for `candidate`
(pldb/db-rel vote voter-name candidate)

(def voter-db (pldb/db
               [vote "Peter" :blue]
               [vote "Sarah" :blue]
               [vote "Larry" :red]
               [vote "Steve" :red]
               [vote "Amy" :yellow]))

(defn candidate-received-no-votes
 
"Relation where candidate `candidate` received no votes"
 
[candidate]
 
(fresh [voter candidate-with-votes]
   
(conda
     
[(vote voter candidate)
     
(!= candidate candidate-with-votes)]
     
;; No candidate received a vote, so `candidate` received no votes
     
[succeed])))

diplomacy.vote> (run-db* voter-db [q] (diplomacy.vote/candidate-received-no-votes :blue))
((_0 :- (!= (_1 :blue))) (_0 :- (!= (_1 :blue))))

This result makes sense because unification succeeds as long as `candidate-with-votes` is not `:blue` (though I'm not sure why there's two results). However, this is not what I wanted: the run should 'fail' because the candidate `:blue` received at least one vote.

The only other thing in the core.logic API that looked promising was `nafc`:

(defn candidate-received-no-votes
 
"Relation where candidate `candidate` received no votes"
 
[candidate]
 
(fresh [voter]
   
(nafc vote voter candidate)))

diplomacy.vote> (run-db* voter-db [q] (diplomacy.vote/candidate-received-no-votes :blue))
((_0 :- (clojure.core.logic/nafc #function[clojure.lang.AFunction/1] _1 :blue)))

This constraint this produces makes sense, but I believe the only correct answer to my query is getting no results: ()

I'm struggling to think of a correct implementation of `candidate-received-no-votes`. Can anyone provide a correct implementation, or point me in the right direction?

Norman Richards

unread,
Dec 27, 2016, 10:26:15 AM12/27/16
to minik...@googlegroups.com
This is not the type of goal we like to write, but here's how you can do it in core.logic:

(defn candidate-received-no-votes [candidate]
  (conda
   [(vote (lvar) candidate)
    fail]
   [succeed]))



conda/condu should both work here.  It basically says, if there is a vote for the candidate, only consider that branch of the cond, which fails. I'm sad to say we've even formalized it in our core.logic support lib:  

(defmacro fail-if
  "fail if the given goal succeeds, use with extreme caution"
  [goal]
  `(conda [~goal fail]
               [succeed]))


We've never had any success with the nafc goal in core.logic.  I'm still not entirely sure what it's supposed to be doing.  It seems to be introducing constraints. If it works, it certainly doesn't play nice with pldb.







Gordon Gustafson

unread,
Dec 27, 2016, 8:53:17 PM12/27/16
to minikanren
Thanks so much for the helpful reply!

This is not the type of goal we like to write.

Is this because it uses conda/condu (which aren't fully relational), or is the "extreme caution" for other reasons? Do you know of any advice or resources that can help me avoid this type of goal for problems that seem to require negation?


I'm sad to say we've even formalized it in our core.logic support lib

Is your support lib available anywhere? I couldn't find it on your Github. I'd love to see the relations an experienced user uses regularly and how they're implemented.
Reply all
Reply to author
Forward
0 new messages