Hi, in the reasoned schemer, they define (Chapter 6 page 105)
(defrel (nevero) (nevero)) and then are able to use it as goal.
1. what actually does 'defrel' do, is there an equivalent?
2. I naively said (defn nevero [s] (nevero s)) , but it makes a stack overflow in the case
(run 1 [q]
(conde
[nevero]
[l/succeed]))
cool thanks @peterhfmnn . I am also using the pattern matching. I find it very condensend and even easier to read once one is used to it!
defrel is defined in the 'Connecting the wires' appendix. It's been awhile since I've looked at core.logic itself, so I'm not sure if there's an exact equivalent there.
But basically you're looking for some way to make this lazy, to break the recursion.
Glancing over the core.logic source though, It seems possible that the definition of defrel could be pretty close. Something like (fn [s] (fn [] (nevero)))
ah,
(defn nevero [s]
(conde [(nevero s)]))
this works.
ah another fn πThat makes sense, I believe conde synthesizes the same structures for you.
ah
ah it makes a stack graph of fn or something
https://github.com/clojure/core.logic/tree/master/src/main/clojure/cljs/core#L1183
You can macroexpand your own usage to see what it turns into
When I was working through the book, I first defined a macro similar to the footnote on page 19:
(defmacro defrel [name params & goals]
`(defn ~name ~params
(fn [s#]
(fn []
((l/and* ~(vec goals)) s#)))))
The l/and* part is just for convenience. I guess the final returned fn is what makes it lazy to prevent infinite recursion.
The all macro in core.logic seems to do the same thing, but with bind, which I donβt quite understand since I am not familiar with protocols in Clojure. So I guess we can also write it like this:
(defmacro defrel [name params & goals]
`(defn ~name ~params
(fn [s#]
(l/bind* s# ~@goals))))Besides that, I sometimes prefer core.logics defne macro that enables more concise definitions using pattern matching (see https://github.com/clojure/core.logic/wiki/A-Core.logic-Primer#pattern-matching). It was fun to rewrite definitions from the book using defne instead:
(defrel teacupo [t]
(or* [(l/== 'tea t) (l/== 'cup t)]))
(l/defne teacupo [t]
(['tea])
(['cup]))
(defne cdro [p d] ([[_ . d] _]))
(defne caro [p a] ([[a . _] _]))
(defne conso [a d p] ([_ _ [a . d]]))
(defne nevero []
([] (nevero)))
(defne alwayso []
([] s#)
([] (alwayso)))