@jballanc: That I've used numbers is just for simplicity. The more general question is: if (thingo x)
can unify x
with both :fork
and :spoon
, is there a way to tell if x
is unified first with :fork
and then :spoon
or the other way round?
@jballanc: Basically, what I am looking for is a way to transform between multiple unifications and a list of the unifications.
tsdh: hmm…if I understand you correctly, I’d be tempted to say that this falls into the category of “implementation detail” in core.logic
that is, if you have, say: (run* [q] (conde [(== q 1) (== q 2)]))
and you want to know did q
match 1 first, or 2 first?
@jballanc: Exactly.
yeah…I mean, IIRC the implementation of conde
and friends is more-or-less a depth-first tree walk, so unifications should happen in roughly the order they’re provided
…but I think that’s definitely “implementation detail” since, as I understand it, in Will Byrd’s ideal world all mini-Kanren conditions would be relational, i.e. order independent
He does a really good job explaining that concept in this podcast: http://www.functionalgeekery.com/episode-9-william-e-byrd/
So, while it might be possible to hack a solution to get what you want, I think you have to keep in mind that you’d be directly controverting one of the goals of mini-Kanren as a logic system
😕
(…but I’m far from an expert on the matter)
@jballanc: Yes, I'm with you in your concrete example. But with your own relations, you can define the order in which things get unified. For example, say you deal with the concepts block and statement in some programming language. Clearly, a block contains statements, and the order of statements in a block does matter. Now you have to choices to model that with relations: 1. (block-has-stmto block stmt)
where the relation unifies stmt
once for each statement in a concrete block, or 2. (block-has-stmts block stmts)
where stmts
gets unified with the list of statements in a concrete block. Variant 1 is much nicer to work with in case you don't care about the order. With variant 2, you have the order but if you don't care about it, queries become a bit more complicated (basically you need membero
goals over the place).
@jballanc: Well, I guess just providing both versions makes everybody happy, and variant 1 can easily be implemented on top of variant 2.
@jballanc: Just the reverse seems to be not so trivial, and of course I started with variant 1. :simple_smile:
tsdh: It’s an interesting use-case to be sure. About the only thing I can think of that might make it easier to work with is if you could describe an ordering relationship between the individual statements. Something like: endif
must come after if
but before enddef
…or something like that. I suspect, though, that you’d quickly find yourself implementing a full parser/AST walker.
…which, to be sure, is definitely an interesting use case. You might be interested to check out Will Byrd’s Quine generator in mini-Kanren, as it has similar-ish elements as I recall.
@jballanc: ok, thanks for the pointer
Another thing: can I define a relation which asserts that some goal succeeds but some other goal fails? I'd be fine with such a must-fail construct was non-relational, that is, only applicable if all logic variables of the goal are ground.
I guess that's easy to implement myself but probably there's already something predefined.
@tsdh I think nafc
(https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L2725) is what you are looking for. See the tests (https://github.com/clojure/core.logic/blob/29a46db8a294b29a37d8046fe7ed52be51f126f0/src/test/clojure/clojure/core/logic/tests.clj#L3169) for examples
@nberger: great, thank you!
@tsdh: you are welcome