-
Notifications
You must be signed in to change notification settings - Fork 157
Reif cookbook #3100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Reif cookbook #3100
Conversation
learn/reif_examples.dj
Outdated
| ## if_/3 | ||
|
|
||
| if_1 calls predicate If_1, adding on the last argument the predicate expects, which is a boolean value, T. | ||
| if T then calls the predicate Then_0 | ||
| otherwise, calls the predicate Else 0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not an expert, but IMO the point of if_/3 is "indexing" it doesn't do any magic you can do everything it does while using dif/2, but it cleverly reduces amount of choice points – which is a real deal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am less of an expert. I understand these predicates are also likely to be more monotonic or pure and therefore harder to write incorrect programs as well as some efficiency considerations. You want to add some language?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I don’t think “indexing” is explained adequately either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My goal at this point is to provide enough examples that make it easier to get going using reif for the basics.
I might (or any other contributor might) add more examples with an explanation of benefits such as efficiency or monotonicity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My goal at this point is to provide enough examples that make it easier to get going using reif for the basics.
Totally. That's why I don't think it helps to explain in terms of jargon like "indexing". I think you're right that if_ should be understand in terms of what it gets YOU, the programmer, in terms of correctness.
UWN
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend to read the cited article first. Not conforming to the naming convention, starting with an incorrect example is not helpful for a tutorial. Instead the major focus should be on using the existing conditions.
|
You keep using the term "reify" in many different senses, which complicates understanding. Are we reifying a predicate? A goal? A condition? A truth value? A definition? A concept? I would stick to only talking about "reified predicates" or predicates "reified by a variable". In
|
I think I have made this more clear. |
|
Ouptput from doclog, so you don't have to run it yourself: |
|
Is this ok now for a first cut? I plan to add to it in another version one i understand how to use (,) and (;). I’d like to get this published first. |
|
Is there any need to mention |
Probably not. Honestly i never tried (->) before writing this tutorial. I’ll address that. I may reintroduce-> and (is) in a later version to illustrate the problems with them. |
UWN
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is a good example of defining reifying membership: https://stackoverflow.com/q/79275439/772868
|
Would FizzBuzz be a good example of how to use reification meaningfully? e.g. ?- use_module(library(reif)).
?- use_module(library(clpz)).
?- N=3,
(0 is N mod 3 -> Fizz = true; Fizz = false),
(0 is N mod 5 -> Buzz = true; Buzz = false),
( Fizz,Buzz -> Answer = "FizzBuzz"
; Fizz -> Answer = "Fizz"
; Buzz -> Answer = "Buzz"
; number_chars(N, Answer)).Versus a version using reif, which has the advantage that the clause order doesn't matter and you can backtrack through different solutions of N with the semicolon key: ?- use_module(library(reif)).
?- use_module(library(clpz)).
?- (N=2;N=3;N=6;N=15),
#=(0, N mod 3, Fizz),
#=(0, N mod 5, Buzz),
(
Fizz=true,Buzz=true,Answer="FizzBuzz"
;Fizz=true,Buzz=false,Answer="Fizz"
;Fizz=false,Buzz=true,Answer="Buzz"
;Fizz=false,Buzz=false,number_chars(N, Answer)
).Can the above be improved maybe? I don't think that 4-way fork can be simplified with use of |
|
Personally, I think a good program makes clear that it follows the specification. Therefore, if we have for example the following specification of FizzBuzz I found online: Given an integer n, for every positive integer i <= n, the task is to print,
"FizzBuzz" if i is divisible by 3 and 5,
"Fizz" if i is divisible by 3,
"Buzz" if i is divisible by 5
"i" as a string, if none of the conditions are true.
Then what about this program: i_output(I, Os) :-
if_((I mod 3 #= 0, I mod 5 #= 0),
Os = "FizzBuzz",
if_(I mod 3 #= 0,
Os = "Fizz",
if_(I mod 5 #= 0,
Os = "Buzz",
number_chars(I, Os)))).
Yielding for example: ?- N = 15, between(1, N, I), i_output(I, Os). N = 15, I = 1, Os = "1" ; N = 15, I = 2, Os = "2" ; N = 15, I = 3, Os = "Fizz" ; N = 15, I = 4, Os = "4" ; N = 15, I = 5, Os = "Buzz" ; N = 15, I = 6, Os = "Fizz" ; N = 15, I = 7, Os = "7" ; N = 15, I = 8, Os = "8" ; N = 15, I = 9, Os = "Fizz" ; N = 15, I = 10, Os = "Buzz" ; N = 15, I = 11, Os = "11" ; N = 15, I = 12, Os = "Fizz" ; N = 15, I = 13, Os = "13" ; N = 15, I = 14, Os = "14" ; N = 15, I = 15, Os = "FizzBuzz". We can test it also in other ways, for instance: Which integers yield ?- length(_, I), catch(i_output(I, "Fizz"), error(syntax_error(_),_), false). I = 3 ; I = 6 ; I = 9 ; I = 12 ; I = 18 ; I = 21 ; I = 24 ; I = 27 ; I = 33 ; I = 36 ; ... . |
|
I think that's reasonable but I still don't love the The more legible but less logically pure alternative is the following, and I imagine there must be a better pure option: i_output_bad(I, Os) :-
(I mod 3 #= 0, I mod 5 #= 0) -> Os = "FizzBuzz"
; (I mod 3 #= 0) -> Os = "Fizz"
; (I mod 5 #= 0) -> Os = "Buzz"
; number_chars(N, Os). |
|
number_canonchars(N, Cs) :-
number_chars(N, Cs),
number_chars(N, Cs1),
Cs1 = Cs.
fizzbuzz(N, Fizzbuzz) :-
match(N, [
((*) | #N mod 3 #= 0, #N mod 5 #= 0) ~> Fizzbuzz = "FizzBuzz",
((*) | #N mod 3 #= 0) ~> Fizzbuzz = "Fizz",
((*) | #N mod 5 #= 0) ~> Fizzbuzz = "Buzz",
(*) ~> number_canonchars(N, Fizzbuzz)
]).
?- length(_,N), fizzbuzz(N, Fb).
N = 0, Fb = "FizzBuzz"
; N = 1, Fb = "1"
; N = 2, Fb = "2"
; N = 3, Fb = "Fizz"
; N = 4, Fb = "4"
; N = 5, Fb = "Buzz"
; N = 6, Fb = "Fizz"
; N = 7, Fb = "7"
; N = 8, Fb = "8"
; N = 9, Fb = "Fizz"
; N = 10, Fb = "Buzz"
; N = 11, Fb = "11"
; N = 12, Fb = "Fizz"
; N = 13, Fb = "13"
; N = 14, Fb = "14"
; N = 15, Fb = "FizzBuzz"
; N = 16, Fb = "16"
; ... .
?- length(_, I), catch(fizzbuzz(I, "Fizz"), error(syntax_error(_),_), false).
I = 3
; I = 6
; I = 9
; I = 12
; I = 18
; I = 21
; I = 24
; ... .This also made me realize a bug on my handling of modules, which was kinda expected given the cursed things I'm doing with them here. |
|
That Qupak example is cool, but it's bringing in a lot! I wonder if it makes sense to think of :- meta_predicate(lift_t(0, ?)).
lift_t(G, true) :- G.
:- meta_predicate(eval_reif(1)).
eval_reif(G_1) :- call(G_1, true).
:- meta_predicate('->'(1, 0, ?)).
'->'(If_1, Then_0, T) :- cond_t(If_1, Then_0, T).
fizzbuzz(I, Os) :- eval_reif((
(I mod 3 #= 0, I mod 5 #= 0) -> Os = "FizzBuzz"
; (I mod 3 #= 0) -> Os = "Fizz"
; (I mod 5 #= 0) -> Os = "Buzz"
; lift_t(number_chars(I,Os))
)).
% e.g.:
% N = 15, between(1, N, I), fizzbuzz(I, Os).
% length(_, I), catch(fizzbuzz(I, "Fizz"), error(syntax_error(_),_), false). |
Is that what cond_t is for? if without the else? |
removed the offending (->) and is. |
Added this example since it shows pretty well how to use if_. |
|
Can it be merged now, at least as the first version? Who is making the decision about which PRs are merged? I presume @mthom? |
rotu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many typos. I'm sure some things can be better explained but I think this is a good start and definitely better than leaving reif undocumented!
learn/reif_examples.dj
Outdated
| What is happening is that reif has provided (=)/3, and that is what is being used in tfilter (not the usual (=)/2). | ||
|
|
||
| But (in my system at the time of writing) (#>)/2 exists, but there is no (#>)/3. | ||
| A workaround is to define a three-arity predicate to do the comparison (it could be (#>)/3, but I choose pound\_gt\_t): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pound_gt_t is just miserable. What's wrong with #>? It's already an operator as defined by clpz.
Otherwise, I'd use greater_t or gt_t.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because (#>)/3 was not available on my system despite loading clpz and reif. That quite confused me and likely any other Prolog beginner.
I also think it is likely (#>)/3 will one day be available so I didn't want to define one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe even one day very soon... #3163
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't mean to cause any trouble :).
Co-authored-by: Dan Rose <DanOfTheRoses@gmail.com>
…prolog into reif_cookbook
A few examples on using reif.