core-logic

telekid 2021-01-12T00:26:42.038700Z

How does recursion work in core.logic? In other words, what does a recursive logic function look like? Trying to develop a mental model for how e.g. a graph traversal algorithm would work.

2021-01-12T01:19:08.040700Z

It looks the same, you have a conde with cases typically a base case that doesn't recurse and a recursive case that does

2021-01-12T01:19:58.041700Z

Very similar structurally to a recursive non-relation

2021-01-12T01:21:20.043400Z

Because they are relations, not functions, what you are doing is establishing relationships between lvars, and recursive relationships are, uh, I think induction

2021-01-12T01:23:07.045100Z

The often look very similar to datalog rules, so maybe you introduce a new lvar in the recursive case like you would in datalog for a join

telekid 2021-01-12T03:00:28.046300Z

interesting, thank you

telekid 2021-01-12T03:00:59.046900Z

I’ll play with it until I build an intuition

2021-01-12T03:18:26.050400Z

so if a list is defined as a recursive data type that is either a cons of some item onto a tail list, or an empty list(nil), you can prove an item is a member of a list like: 1. the list is either nil or a cons 2. if the list is nil the proof has failed 3. if the list is a cons and the item in the cons is the same as the item you are looking for, you are done 4. if the list is a cons and the item in the cons is not the same, prove that the item you are looking for is in the tail

emccue 2021-01-12T03:20:47.050700Z

look at ACL2S proofs for contains

emccue 2021-01-12T03:20:55.050900Z

or member or whatever the equivalent is

2021-01-12T03:22:41.051700Z

which written as core.logic looks like:

(defn membero
  [x l]
  (l/conde
   [(l/== nil l) l/fail]
   [(l/fresh [_]
      (l/conso x _ l))]
   [(l/fresh [_ y]
      (l/conso _ y l)
      (membero x y))]))
Or something, the nil bit might not actually work

2021-01-12T03:23:15.052200Z

you can leave the l/fail case out, if nothing matches it is fail

2021-01-12T03:23:31.052600Z

and core.logic has some macros for doing sort of pattern matchy kinds of things

2021-01-12T03:24:08.053100Z

the actual definition of membero looks like:

(defne membero
  "A relation where l is a collection, such that l contains x."
  [x l]
  ([_ [x . tail]])
  ([_ [head . tail]]
    (membero x tail)))

2021-01-12T03:24:37.053600Z

which is the same set of two cases leaving the nil case out

2021-01-12T03:25:18.054Z

then moving from lists to trees (or graphs) you just add more cases

2021-01-12T03:25:45.054600Z

so instead of a single case for the tail of the list you have a case for the left or right branch of a tree or whatever

2021-01-12T03:29:18.056Z

which is part of the magic of core.logic, all the cases are explored simultaneously for you, so if you have more than one recursive case it is fine, and you don't have to worry about backtracking and trying another branch

2021-01-12T03:34:01.057800Z

something to keep in mind as well is core.logic has built in support for working with lists relationally (firsto, resto, conso, etc) and if you have some custom graph data structure, you'll either have to write your own relations for constructing/deconstructing nodes in the graph, or operate it non-relationally, which can trip you up

👍 1