From 6b13523f17dac0a2bef3dd69bdf508de04c477fa Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 22 Sep 2025 10:47:35 -0700 Subject: [PATCH 01/11] added examples. --- doclog.config.pl | 4 +- learn/reif_examples/reif_examples.dj | 303 +++++++++++++++++++++++++++ 2 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 learn/reif_examples/reif_examples.dj diff --git a/doclog.config.pl b/doclog.config.pl index d245d801b..f20151171 100644 --- a/doclog.config.pl +++ b/doclog.config.pl @@ -7,8 +7,10 @@ learn_pages_categories(["First steps", "Tutorials"]). learn_pages([ page("Let's play Brisca", "Tutorials", "lets-play-brisca.dj"), - page("Test page", "First steps", "test-page.dj") + page("Test page", "First steps", "test-page.dj"), + page("reif_examples", "Tutorials", "reif_examples/reif_examples.dj") ]). copy_file("logo/scryer.png", "scryer.png"). copy_file("learn/Spanish_deck_Fournier.jpg", "learn/Spanish_deck_Fournier.jpg"). copy_file("learn/brisca-interactive.png", "learn/brisca-interactive.png"). + \ No newline at end of file diff --git a/learn/reif_examples/reif_examples.dj b/learn/reif_examples/reif_examples.dj new file mode 100644 index 000000000..4d4957a7f --- /dev/null +++ b/learn/reif_examples/reif_examples.dj @@ -0,0 +1,303 @@ +# reif Cookbook +This tutorial shows some examples of using the predicates in [reif](/reif). +Load lambda, dif, clpz, and reif into your toplevel to evaluate the examples in your toplevel. + +If you have an improvement (such as a better example or an explanation) to this tutorial, please [submit a PR](https://github.com/mthom/scryer-prolog/pulls) or +[github issue](https://github.com/mthom/scryer-prolog/issues). + +## Introduction and meta_predicate Review +Review the summary at 25:45 [Power of Prolog meta_predicate declarations](https://www.youtube.com/watch?v=m3cbgebcKng). You will need some understanding of meta_predicate declarations. + +The meta-predicate declarations in reif.pl typically additional arguments are required for a supplied predicate as an argument; the last additional argument will be a reified binary value. + + In this case, the first argument of tfilter is required to be a predicate taking two additional arguments. + +```prolog +:- meta_predicate(tfilter(2, ?, ?)). +''' + +You will probably need to inspect reif.pl to fully understand how to use the module, and to learn +some prolog skills you may not already have. + +There is some code that you may find confusing, which shows a predicate expecting 2 arguments, but only one is provided: +```prolog + if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs), +''' +Fortunatley, you don't need to understand that mechanism to use the reif module. Below there examples of how to use if_. + + +Also, don't be confused when something like this works: +```prolog +?- call( tfilter,=(3),[3],X). + X = [3]. +?- +''' +but this breaks. + +```prolog +?- call( tfilter,#>(3),[3],X). + error(existence_error(procedure,(#>)/3),(#>)/3). +?- +''' +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): +```prolog +pound_gt(X,Y,true):- X #>Y,!. +pound_gt(_,_,false). + +?- tfilter(pound_gt(3),[1,3],T). + T = [1]. +?- +''' +pound_gt is not very robust, using "!" for example. If you are writing predicates to use with reif, look at the implementation =/3 in reif. + +## memberd_t/3 + +Query holds if a single item 'c' is a member of a list. + +```prolog +?- memberd_t('c',"branch free",true). + true. +''' +Query holds if single item is excluded from a list. Exclusion or inclusion is determined by the third argument. + +```prolog +?- memberd_t('c',"branch free",false). + true. +''' + +Query holds, and X is true if and only if a single item is included in the list. Note single quotes are normally not needed around atoms like 'c'. + +```prolog +?- memberd_t(c,"branch free",X). + X = true. +?- +''' +Query holds for Y in a member of the list and X is false or Y is not a member of the list and X is true. + +```prolog +?- memberd_t(Y,[1,2,3],X). + Y = 1, X = true +; Y = 2, X = true +; Y = 3, X = true +; X = false, dif:dif(1,Y), dif:dif(2,Y), dif:dif(3,Y). +?- +``` +Lists of length 2, where A is a member of exactly one of those lists. + +```prolog +length(L1,2),length(L2,2),memberd_t(A,L1,X), memberd_t(A,L2,Y), dif(X,Y). + L1 = [A,_C], L2 = [_A,_B], X = true, Y = false, dif:dif(_A,A), dif:dif(_B,A) +; L1 = [_A,A], L2 = [_B,_C], X = true, Y = false, dif:dif(_A,A), dif:dif(_B,A), dif:dif(_C,A) +; L1 = [_A,_B], L2 = [A,_C], X = false, Y = true, dif:dif(_A,A), dif:dif(_B,A) +; L1 = [_A,_B], L2 = [_C,A], X = false, Y = true, dif:dif(_A,A), dif:dif(_B,A), dif:dif(_C,A) +; false. +?- +''' +## (=)(A,B,T). + +reif introdces =/3, which holds if and only if the first two arguments are equal, and the third argument T is true or the first two arguments are not equal the the third argument is false. T is the 'reified' truth value of A. + +``` prolog +?- (reif:(=)(1,2,false). + true. +?- (reif:(=)(2,2,false). + false. +?- (reif:(=)(2,2,true). + true. +?- + +''' + +You may find it useful to write predicates where the last argument is a boolean variable containing the result of whether some relation holds, for use with other reif predicates. + + + +## 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. + +It is worth looking at the source. +```prolog +if_(If_1, Then_0, Else_0) :- + call(If_1, T), + ( T == true -> call(Then_0) + ; T == false -> call(Else_0) + ; nonvar(T) -> throw(error(type_error(boolean, T), _)) + ; throw(error(instantiation_error, _)) + ). +''' +```prolog +?- if_( (X=3),(Y=4),(Z=5)), (X=4;X=3). + X = 3, Y = 4 +; X = 4, Z = 5 +; false. +?- +''' +In the above example, only Y or Z are instantiated variables, but not both. + +Example with a differrent comparison predicate. + +```prolog +greater_than_two(Y,T) :- Y #> 2 ,T=true. +greater_than_two(Y,T) :- Y #< 2 ,T=false. +?- if_(greater_than_two(3),X="works", X="fails"). + X = "works". +?- +''' + +## tfilter/3 + +tfilter/3 is a predicate for filtering lists. + +Again, worth reading the source, because it shows some prolog technique that +may be new to you (unless you are a prolog expert already). + +```prolog +:- meta_predicate(tfilter(2, ?, ?)). +tfilter(_, [], []). +tfilter(C_2, [E|Es], Fs0) :- + if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs), + tfilter(C_2, Es, Fs). +``` +The meta_predicate directive is important. It specifies the first parameter to tfilter is a predicate needing two more arguments. The first required argument is the value to be compared from the list, and the second is the reified result of the comparison (true, or false). + +If your prolog system has #3: +```prolog +?- tfilter(#>(10),[1,20,20], Xs). + error(existence_error(procedure,(#>)/3),(#>)/3). +?- + +''' + +Relating a list, to a list without a certain element: +```prolog +?- tfilter(dif(10),[1,2,3,X],Es). + X = 10, Es = [1,2,3] +; Es = [1,2,3,X], dif:dif(10,X). +?- ''' + +See which predicates produce a non-empty list with tfilter. + +```prolog +?- (X= =(3); X= #<(4); X= =(100) ), tfilter(X,[1,2,3,4,6],Y), Y\=[]. + X = =(3), Y = [3] +; X = #<(4), Y = [6] +; false. +?- ''' + + +## tmember/2 +Just like tfilter, tmembers first argument is a paritally applied 2-arity predicate. +- meta_predicate(tmember(2, ?)). + +```prolog +?- tmember(=(3),[1,2,3,4,6]). + true. +?- + +''' + +It can be used to test for existance of an element for which the supplied predicate holds. +```prolog +?- tmember(#<(1),[1,2,3,4,6]). + true. +?- tmember(#<(12),[1,2,3,4,6]). + false. +?- +''' + ## tmember/3 + +tmember_t can be used to test the existance or non-existance of an element of the list, for which a predicate holds. + +```prolog +?- tmember_t(#<(1),[1,2,3,4,6],T). + T = true. +?- tmember_t(#<(100),[1,2,3,4,6],T). + T = false. +?- + +''' + + ## tpartition/4 +Partition a list based on a partially applied 2-arity predicate. + + ```prolog + :- meta_predicate(tpartition(2, ?, ?, ?)). + ''' + Partition a list based on larger than 4 + ```prolog +?- tpartition(#<(4),[1,2,3,4,5,6,3,4,5],A,B). + A = [5,6,5], B = [1,2,3,4,3,4]. +?- +''' +Find Z, for which #<(Z) partions [1,2,4,5] into [4,5], and [1,2]: +```prolog +?- tpartition(#<(Z),[1,2,4,5],[4,5],[1,2]), indomain(Z). + Z = 2 +; Z = 3 +; false. +?- + +''' +## if_/3 + +[if_/3](https://www.metalevel.at/prolog/metapredicates) "correctly commits to one of two alternatives when admissable …". + +The first argument is a predicate requiring one more argument, which is the reified truth value of a comparsion . + +The prolog system provides some help here. The prolog system uses =/3 in this example, because =/3 wouldn't match. + +```prolog +?- if_(X=8, Z=3, M=4). +''' +or +```prolog +?- if_(X#<8, Z=3, M=4). + M = 4, clpz:(X in 8..sup), clpz:(X+1#=_A), clpz:(_A in 9..sup) +; Z = 3, clpz:(X in inf..7), clpz:(X+1#=_A), clpz:(_A in inf..8). +?- +''' + + +Attemtping to use a 0-ary predicate fails: +```prolog +?- Y=true, if_(Y, Z=3, M=4). + error(existence_error(procedure,true/1),true/1). +?- +''' +Which you can easily work around with: +```prolog +?- Y=true,if_(Y=true, Z=3, M=4). + Y = true, Z = 3. +?- +''' + +## cond_t/3 + +Seems to be an if construct without an else. + +```prolog +?- cond_t(A=B,format("A is B",[]), true),A=west,B=west. +A is B A = west, B = west +; false. +``` + +```prolog +?- cond_t(A=B,format("A is not B",[]), false),A=wild,B=one. +A is not B A = wild, B = one. +``` +## ,/3 and ;/3 + +Todo: Explain how ,/3 and ;/3 are to be used, and how they are used internally withing reif. + \ No newline at end of file From a2986146103d10ffd18930ea88e4d2447b35f4c0 Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 22 Sep 2025 18:00:22 -0700 Subject: [PATCH 02/11] move file --- doclog.config.pl | 8 +++++++- learn/{reif_examples => }/reif_examples.dj | 0 2 files changed, 7 insertions(+), 1 deletion(-) rename learn/{reif_examples => }/reif_examples.dj (100%) diff --git a/doclog.config.pl b/doclog.config.pl index f20151171..474bf0d91 100644 --- a/doclog.config.pl +++ b/doclog.config.pl @@ -4,12 +4,18 @@ websource("https://github.com/mthom/scryer-prolog/tree/master/src/lib"). omit(["ops_and_meta_predicates.pl", "tabling"]). learn_pages_source_folder("learn"). +reif_learn_source_folder("learn/reif_examples"). learn_pages_categories(["First steps", "Tutorials"]). +reif_learn_pages_categories( ["First steps", "Tutorials"]). learn_pages([ page("Let's play Brisca", "Tutorials", "lets-play-brisca.dj"), page("Test page", "First steps", "test-page.dj"), - page("reif_examples", "Tutorials", "reif_examples/reif_examples.dj") + page("reif", "Tutorials", "reif_examples/reif_examples.dj") ]). +reif_learn_pages([ + page("reif", "Tutorials", "reif_examples.dj") +]). + copy_file("logo/scryer.png", "scryer.png"). copy_file("learn/Spanish_deck_Fournier.jpg", "learn/Spanish_deck_Fournier.jpg"). copy_file("learn/brisca-interactive.png", "learn/brisca-interactive.png"). diff --git a/learn/reif_examples/reif_examples.dj b/learn/reif_examples.dj similarity index 100% rename from learn/reif_examples/reif_examples.dj rename to learn/reif_examples.dj From a1897a51a96302e5b3775bd70883cf3b01f0e39e Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 24 Sep 2025 16:04:53 -0700 Subject: [PATCH 03/11] some edits --- doclog.config.pl | 6 +- learn/reif_examples.dj | 200 +++++++++++++++++++++++++++-------------- 2 files changed, 132 insertions(+), 74 deletions(-) diff --git a/doclog.config.pl b/doclog.config.pl index 474bf0d91..b1d73df6d 100644 --- a/doclog.config.pl +++ b/doclog.config.pl @@ -4,16 +4,12 @@ websource("https://github.com/mthom/scryer-prolog/tree/master/src/lib"). omit(["ops_and_meta_predicates.pl", "tabling"]). learn_pages_source_folder("learn"). -reif_learn_source_folder("learn/reif_examples"). learn_pages_categories(["First steps", "Tutorials"]). reif_learn_pages_categories( ["First steps", "Tutorials"]). learn_pages([ page("Let's play Brisca", "Tutorials", "lets-play-brisca.dj"), page("Test page", "First steps", "test-page.dj"), - page("reif", "Tutorials", "reif_examples/reif_examples.dj") -]). -reif_learn_pages([ - page("reif", "Tutorials", "reif_examples.dj") + page("reif", "Tutorials", "reif_examples.dj") ]). copy_file("logo/scryer.png", "scryer.png"). diff --git a/learn/reif_examples.dj b/learn/reif_examples.dj index 4d4957a7f..060f19ab9 100644 --- a/learn/reif_examples.dj +++ b/learn/reif_examples.dj @@ -1,83 +1,102 @@ # reif Cookbook -This tutorial shows some examples of using the predicates in [reif](/reif). + +This tutorial shows some examples of using the predicates in [reif](/reif.html). Load lambda, dif, clpz, and reif into your toplevel to evaluate the examples in your toplevel. If you have an improvement (such as a better example or an explanation) to this tutorial, please [submit a PR](https://github.com/mthom/scryer-prolog/pulls) or [github issue](https://github.com/mthom/scryer-prolog/issues). ## Introduction and meta_predicate Review + Review the summary at 25:45 [Power of Prolog meta_predicate declarations](https://www.youtube.com/watch?v=m3cbgebcKng). You will need some understanding of meta_predicate declarations. -The meta-predicate declarations in reif.pl typically additional arguments are required for a supplied predicate as an argument; the last additional argument will be a reified binary value. +Typically, reif predicates provided as arguments typically require the last additional argument will be a reified binary value. In this case, the first argument of tfilter is required to be a predicate taking two additional arguments. -```prolog +``` :- meta_predicate(tfilter(2, ?, ?)). -''' +``` You will probably need to inspect reif.pl to fully understand how to use the module, and to learn some prolog skills you may not already have. There is some code that you may find confusing, which shows a predicate expecting 2 arguments, but only one is provided: -```prolog + +``` if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs), -''' +``` Fortunatley, you don't need to understand that mechanism to use the reif module. Below there examples of how to use if_. Also, don't be confused when something like this works: -```prolog +``` ?- call( tfilter,=(3),[3],X). X = [3]. ?- -''' +``` but this breaks. -```prolog +``` ?- call( tfilter,#>(3),[3],X). error(existence_error(procedure,(#>)/3),(#>)/3). ?- -''' +``` 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): -```prolog + +``` pound_gt(X,Y,true):- X #>Y,!. pound_gt(_,_,false). ?- tfilter(pound_gt(3),[1,3],T). T = [1]. ?- -''' +``` + pound_gt is not very robust, using "!" for example. If you are writing predicates to use with reif, look at the implementation =/3 in reif. +You might wonder if you can write a predicate to relate a predicate with a reified value as the last parameter. + +``` +unreif_reif(P1, P2). +``` + +so that P1(A1, A2, ...AN) holds when P2(A1, A2, ..., AN, T) holds and T is the reified value of P1(A1...AN). + +[Probably not](https://github.com/mthom/scryer-prolog/discussions/2557), but you can probably learn something about writing reified versions of predicates by reading that discussion. + +You can look at predicates like dif/3 or =/3 in [reif](/reif.html) to get ideas about writing predicates that include a reifed boolean value. +``` + ## memberd_t/3 Query holds if a single item 'c' is a member of a list. -```prolog +``` ?- memberd_t('c',"branch free",true). true. -''' +``` Query holds if single item is excluded from a list. Exclusion or inclusion is determined by the third argument. -```prolog +``` ?- memberd_t('c',"branch free",false). true. -''' +``` Query holds, and X is true if and only if a single item is included in the list. Note single quotes are normally not needed around atoms like 'c'. -```prolog +``` ?- memberd_t(c,"branch free",X). X = true. ?- -''' +``` + Query holds for Y in a member of the list and X is false or Y is not a member of the list and X is true. -```prolog +``` ?- memberd_t(Y,[1,2,3],X). Y = 1, X = true ; Y = 2, X = true @@ -85,9 +104,10 @@ Query holds for Y in a member of the list and X is false or Y is not a member of ; X = false, dif:dif(1,Y), dif:dif(2,Y), dif:dif(3,Y). ?- ``` + Lists of length 2, where A is a member of exactly one of those lists. -```prolog +``` length(L1,2),length(L2,2),memberd_t(A,L1,X), memberd_t(A,L2,Y), dif(X,Y). L1 = [A,_C], L2 = [_A,_B], X = true, Y = false, dif:dif(_A,A), dif:dif(_B,A) ; L1 = [_A,A], L2 = [_B,_C], X = true, Y = false, dif:dif(_A,A), dif:dif(_B,A), dif:dif(_C,A) @@ -95,8 +115,9 @@ length(L1,2),length(L2,2),memberd_t(A,L1,X), memberd_t(A,L2,Y), dif(X,Y). ; L1 = [_A,_B], L2 = [_C,A], X = false, Y = true, dif:dif(_A,A), dif:dif(_B,A), dif:dif(_C,A) ; false. ?- -''' -## (=)(A,B,T). +``` + +## (=)(A,B,T). reif introdces =/3, which holds if and only if the first two arguments are equal, and the third argument T is true or the first two arguments are not equal the the third argument is false. T is the 'reified' truth value of A. @@ -109,7 +130,7 @@ reif introdces =/3, which holds if and only if the first two arguments are equal true. ?- -''' +``` You may find it useful to write predicates where the last argument is a boolean variable containing the result of whether some relation holds, for use with other reif predicates. @@ -122,7 +143,7 @@ if T then calls the predicate Then_0 otherwise, calls the predicate Else 0. It is worth looking at the source. -```prolog +``` if_(If_1, Then_0, Else_0) :- call(If_1, T), ( T == true -> call(Then_0) @@ -130,25 +151,27 @@ if_(If_1, Then_0, Else_0) :- ; nonvar(T) -> throw(error(type_error(boolean, T), _)) ; throw(error(instantiation_error, _)) ). -''' -```prolog +``` + +``` ?- if_( (X=3),(Y=4),(Z=5)), (X=4;X=3). X = 3, Y = 4 ; X = 4, Z = 5 ; false. ?- -''' +``` + In the above example, only Y or Z are instantiated variables, but not both. Example with a differrent comparison predicate. -```prolog +``` greater_than_two(Y,T) :- Y #> 2 ,T=true. greater_than_two(Y,T) :- Y #< 2 ,T=false. ?- if_(greater_than_two(3),X="works", X="fails"). X = "works". ?- -''' +``` ## tfilter/3 @@ -157,99 +180,134 @@ tfilter/3 is a predicate for filtering lists. Again, worth reading the source, because it shows some prolog technique that may be new to you (unless you are a prolog expert already). -```prolog +``` :- meta_predicate(tfilter(2, ?, ?)). tfilter(_, [], []). tfilter(C_2, [E|Es], Fs0) :- if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs), tfilter(C_2, Es, Fs). ``` + The meta_predicate directive is important. It specifies the first parameter to tfilter is a predicate needing two more arguments. The first required argument is the value to be compared from the list, and the second is the reified result of the comparison (true, or false). -If your prolog system has #3: -```prolog +``` + +Oddly, scryer prolog 0.9.4-614 has + +``` +#3 + ```: + +``` ?- tfilter(#>(10),[1,20,20], Xs). error(existence_error(procedure,(#>)/3),(#>)/3). ?- -''' +``` Relating a list, to a list without a certain element: -```prolog +``` ?- tfilter(dif(10),[1,2,3,X],Es). X = 10, Es = [1,2,3] ; Es = [1,2,3,X], dif:dif(10,X). -?- ''' +?- +``` See which predicates produce a non-empty list with tfilter. -```prolog +``` ?- (X= =(3); X= #<(4); X= =(100) ), tfilter(X,[1,2,3,4,6],Y), Y\=[]. X = =(3), Y = [3] ; X = #<(4), Y = [6] ; false. -?- ''' - +?- +``` ## tmember/2 -Just like tfilter, tmembers first argument is a paritally applied 2-arity predicate. -- meta_predicate(tmember(2, ?)). -```prolog +Just like tfilter, tmember's first argument is a paritally applied 2-arity predicate: + +``` +:- meta_predicate(tmember(2, ?)). +``` + +``` ?- tmember(=(3),[1,2,3,4,6]). true. ?- -''' +``` + It can be used to test for existance of an element for which the supplied predicate holds. -```prolog + +``` ?- tmember(#<(1),[1,2,3,4,6]). true. ?- tmember(#<(12),[1,2,3,4,6]). false. ?- -''' - ## tmember/3 -tmember_t can be used to test the existance or non-existance of an element of the list, for which a predicate holds. +``` + -```prolog +## tmember_t + + tmembert can be used to test the existance or non-existance of an element of the list, + for which a predicate holds. + + +``` ?- tmember_t(#<(1),[1,2,3,4,6],T). T = true. ?- tmember_t(#<(100),[1,2,3,4,6],T). T = false. ?- -''' +``` ## tpartition/4 -Partition a list based on a partially applied 2-arity predicate. - ```prolog +Partition a list based on a predicate requiring two more arguments. + + ``` :- meta_predicate(tpartition(2, ?, ?, ?)). - ''' - Partition a list based on larger than 4 - ```prolog + ``` + Partition a list based on larger than 4: + + ``` ?- tpartition(#<(4),[1,2,3,4,5,6,3,4,5],A,B). A = [5,6,5], B = [1,2,3,4,3,4]. ?- -''' +``` + Find Z, for which #<(Z) partions [1,2,4,5] into [4,5], and [1,2]: -```prolog + +``` ?- tpartition(#<(Z),[1,2,4,5],[4,5],[1,2]), indomain(Z). Z = 2 ; Z = 3 ; false. ?- -''' +``` + ## if_/3 [if_/3](https://www.metalevel.at/prolog/metapredicates) "correctly commits to one of two alternatives when admissable …". @@ -258,42 +316,46 @@ The first argument is a predicate requiring one more argument, which is the rei The prolog system provides some help here. The prolog system uses =/3 in this example, because =/3 wouldn't match. -```prolog +``` ?- if_(X=8, Z=3, M=4). -''' +``` + or -```prolog + +``` ?- if_(X#<8, Z=3, M=4). M = 4, clpz:(X in 8..sup), clpz:(X+1#=_A), clpz:(_A in 9..sup) ; Z = 3, clpz:(X in inf..7), clpz:(X+1#=_A), clpz:(_A in inf..8). ?- -''' +``` Attemtping to use a 0-ary predicate fails: -```prolog + +``` ?- Y=true, if_(Y, Z=3, M=4). error(existence_error(procedure,true/1),true/1). ?- -''' +``` Which you can easily work around with: -```prolog + +``` ?- Y=true,if_(Y=true, Z=3, M=4). Y = true, Z = 3. ?- -''' +``` ## cond_t/3 Seems to be an if construct without an else. -```prolog +``` ?- cond_t(A=B,format("A is B",[]), true),A=west,B=west. A is B A = west, B = west ; false. ``` -```prolog +``` ?- cond_t(A=B,format("A is not B",[]), false),A=wild,B=one. A is not B A = wild, B = one. ``` From 7195310a01ff9a154f4d7d32396fdfa5db536e30 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 25 Sep 2025 17:41:55 -0700 Subject: [PATCH 04/11] updated based on pr feedback --- learn/reif_examples.dj | 61 +++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/learn/reif_examples.dj b/learn/reif_examples.dj index 060f19ab9..677436c29 100644 --- a/learn/reif_examples.dj +++ b/learn/reif_examples.dj @@ -6,35 +6,59 @@ Load lambda, dif, clpz, and reif into your toplevel to evaluate the examples in If you have an improvement (such as a better example or an explanation) to this tutorial, please [submit a PR](https://github.com/mthom/scryer-prolog/pulls) or [github issue](https://github.com/mthom/scryer-prolog/issues). -## Introduction and meta_predicate Review +## Introduction -Review the summary at 25:45 [Power of Prolog meta_predicate declarations](https://www.youtube.com/watch?v=m3cbgebcKng). You will need some understanding of meta_predicate declarations. +reif predicates will have as an argument a predicate requiring at least one additional argument. That predicate's last argument will be the reified value of the predicate. -Typically, reif predicates provided as arguments typically require the last additional argument will be a reified binary value. +For example, the argument to tfilter is a predicate taking two additional arguments. Inspecting the source, you see the parameters for the first argument +is named C_2; the naming of parameters ending in _N is used to convey the paremeter will be a predicate taking N additional arguments (in reif, the last of which is expected +to be a reifed boolean value). - In this case, the first argument of tfilter is required to be a predicate taking two additional arguments. ``` :- meta_predicate(tfilter(2, ?, ?)). + +tfilter(_, [], []). +tfilter(C_2, [E|Es], Fs0) :- + … +``` + +C_2 can be a partial goal requring two more arguments, or a 2-ary predicate. In either case the last argument is the reified +truth value. +For example, using dif/3 from reif, and applying one argument 3, gives a partially applied goal X_2 requiring two more arguments. + ``` +?- X_2=dif(3), call(X_2,9,T). + X_2 = dif(3), T = true. +?- +``` +or more succinctly: -You will probably need to inspect reif.pl to fully understand how to use the module, and to learn -some prolog skills you may not already have. +``` +?- call(dif(3),9,T). + T = true. +?- +``` + +You will probably need to inspect reif.pl to fully understand how to use the module . By studying the implementation of predicates, you may also learn +some new prolog skills There is some code that you may find confusing, which shows a predicate expecting 2 arguments, but only one is provided: ``` if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs), ``` -Fortunatley, you don't need to understand that mechanism to use the reif module. Below there examples of how to use if_. +Fortunatley, you don't need to understand that mechanism to use the reif module. The C_2 parameter name gives you enough information about the predicate +you must supply as an argument. +You may be surprised when something like this works: -Also, don't be confused when something like this works: ``` ?- call( tfilter,=(3),[3],X). X = [3]. ?- ``` + but this breaks. ``` @@ -42,6 +66,7 @@ but this breaks. error(existence_error(procedure,(#>)/3),(#>)/3). ?- ``` + 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. @@ -69,7 +94,6 @@ so that P1(A1, A2, ...AN) holds when P2(A1, A2, ..., AN, T) holds and T is the r [Probably not](https://github.com/mthom/scryer-prolog/discussions/2557), but you can probably learn something about writing reified versions of predicates by reading that discussion. You can look at predicates like dif/3 or =/3 in [reif](/reif.html) to get ideas about writing predicates that include a reifed boolean value. -``` ## memberd_t/3 @@ -134,25 +158,12 @@ reif introdces =/3, which holds if and only if the first two arguments are equal You may find it useful to write predicates where the last argument is a boolean variable containing the result of whether some relation holds, for use with other reif predicates. - - ## 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. -It is worth looking at the source. -``` -if_(If_1, Then_0, Else_0) :- - call(If_1, T), - ( T == true -> call(Then_0) - ; T == false -> call(Else_0) - ; nonvar(T) -> throw(error(type_error(boolean, T), _)) - ; throw(error(instantiation_error, _)) - ). -``` - ``` ?- if_( (X=3),(Y=4),(Z=5)), (X=4;X=3). X = 3, Y = 4 @@ -166,8 +177,8 @@ In the above example, only Y or Z are instantiated variables, but not both. Example with a differrent comparison predicate. ``` -greater_than_two(Y,T) :- Y #> 2 ,T=true. -greater_than_two(Y,T) :- Y #< 2 ,T=false. +greater_than_two(Y,true) :- Y #> 2. +greater_than_two(Y,false) :- Y #=< 2. ?- if_(greater_than_two(3),X="works", X="fails"). X = "works". ?- @@ -312,6 +323,8 @@ Find Z, for which #<(Z) partions [1,2,4,5] into [4,5], and [1,2]: [if_/3](https://www.metalevel.at/prolog/metapredicates) "correctly commits to one of two alternatives when admissable …". + + The first argument is a predicate requiring one more argument, which is the reified truth value of a comparsion . The prolog system provides some help here. The prolog system uses =/3 in this example, because =/3 wouldn't match. From a47937341eee9d7354bb7faf2bbd2c5fa9fa56b2 Mon Sep 17 00:00:00 2001 From: Doug Date: Sun, 5 Oct 2025 09:09:15 -0700 Subject: [PATCH 05/11] incorporation some feedback. --- learn/reif_examples.dj | 93 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 9 deletions(-) diff --git a/learn/reif_examples.dj b/learn/reif_examples.dj index 677436c29..0c530b410 100644 --- a/learn/reif_examples.dj +++ b/learn/reif_examples.dj @@ -8,13 +8,86 @@ If you have an improvement (such as a better example or an explanation) to this ## Introduction -reif predicates will have as an argument a predicate requiring at least one additional argument. That predicate's last argument will be the reified value of the predicate. +Here are predicates exported by reif. +``` +:- module(reif, [if_/3, (=)/3, (',')/3, (;)/3, cond_t/3, dif/3, + memberd_t/3, tfilter/3, tmember/2, tmember_t/3, + tpartition/4]). +``` + +The last argument of (=)/3, (,)/3, (;)/3, dif/3, or the predicates with principal functor ending in "_t" is the reified boolean value of the predicate. The _t +suffix of a functor name for a predicate expecting a reified boolean value is a convention, as is naming the corresponding argument or parameter T. +You may wish to follow that convention when writing your own predictes. -For example, the argument to tfilter is a predicate taking two additional arguments. Inspecting the source, you see the parameters for the first argument -is named C_2; the naming of parameters ending in _N is used to convey the paremeter will be a predicate taking N additional arguments (in reif, the last of which is expected -to be a reifed boolean value). +### What is a reified boolean value? +In prolog it means representing the truth of some expression or relation as a boolean value. Unlike many languages, the +truthyness of a term like 'A < 10' can not be directly bound to a variable with an assignment. This is because terms have a different meaning in prolog +that you should already be familiar with. +``` +?- A is 112, C= (A<10). + A = 112, C = (112<10). +?- +``` +To make C bound to a boolean value with the built in (->): + +``` +?- A is 2, ( A#<10 -> C=true;C=false), C, format("~s",["C holds"]). +C holds A = 2, C = true. +?- A is 2000, ( A#<10 -> C=true;C=false), C, format("~s",["C holds"]). + false. +?- +``` + + _if from reif provides a better way to do the same. +``` +?- A #= 2,if_(A#<103,C=true,C=false),C,format("~s",["C Holds"]). +C Holds A = 2, C = true. +?- +``` + +true holds (and false doesn't), even when bound to variables: + +``` +?- X=true,X, format("foo",[]). +foo X = true. +?- X=false,X, format("foo",[]). + false. +?- +``` + +oddly, there is no build in < notation in prolog for boolean values. +``` +?- false < true, true. + error(type_error(evaluable,false/0),(is)/2). +?- +``` + + +Note that other Prolog modules may express a reified boolean value as 0 or 1 or choose some other representation instead of false and true. + + +### Naming Conventions in reif + +We will use tmember_t to demonstrate an example. T is bound to true when a condition holds, and false when it doesn't. + +``` +?- tmember_t(#<(1),[1,2,3,4,6],T). + T = true. +?- tmember_t(#<(100),[1,2,3,4,6],T). + T = false. +?- +``` + +The prefix of "t_" (tmember/2,tmember_t/3, tfilter, tpartition/4) in a predicate name indicates the first +argument will be a predicate that takes as as an argument a predicate (or partially applied predicate) taking additonal arguments, the last of which will +be a reified boolean value for whether the query holds. + +The naming convention for the parameters which are predicates is C_N, where C may convey some meaning about the arguments purpose, and the +N indicates how many additional arguments are required by the predicate. + +It is necessary useful to inspect the source of reif so you can see the information conveyed in the predicate and parameter names. ``` :- meta_predicate(tfilter(2, ?, ?)). @@ -22,9 +95,9 @@ tfilter(_, [], []). tfilter(C_2, [E|Es], Fs0) :- … ``` +C_2 can be a partial goal requring two more arguments, or a 2-ary predicate. In either case the parameter of C_2 is the reified +truth value. -C_2 can be a partial goal requring two more arguments, or a 2-ary predicate. In either case the last argument is the reified -truth value. For example, using dif/3 from reif, and applying one argument 3, gives a partially applied goal X_2 requiring two more arguments. ``` @@ -51,6 +124,8 @@ There is some code that you may find confusing, which shows a predicate expectin Fortunatley, you don't need to understand that mechanism to use the reif module. The C_2 parameter name gives you enough information about the predicate you must supply as an argument. +### Surprises + You may be surprised when something like this works: ``` @@ -70,7 +145,7 @@ but this breaks. 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): +A workaround is to define a three-arity predicate to do the comparison (it could be #>/3, but I choose pound_gt_t): ``` pound_gt(X,Y,true):- X #>Y,!. @@ -100,13 +175,13 @@ You can look at predicates like dif/3 or =/3 in [reif](/reif.html) to get ideas Query holds if a single item 'c' is a member of a list. ``` -?- memberd_t('c',"branch free",true). +?- memberd_t(c,"branch free",true). true. ``` Query holds if single item is excluded from a list. Exclusion or inclusion is determined by the third argument. ``` -?- memberd_t('c',"branch free",false). +?- memberd_t(c,"branch free",false). true. ``` From 2bf4f5ea11ab2fa95e500dbc44f1bbf6e53614d4 Mon Sep 17 00:00:00 2001 From: Doug Date: Sun, 5 Oct 2025 15:18:53 -0700 Subject: [PATCH 06/11] incorporating feedback --- learn/reif_examples.dj | 165 +++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 82 deletions(-) diff --git a/learn/reif_examples.dj b/learn/reif_examples.dj index 0c530b410..86800530d 100644 --- a/learn/reif_examples.dj +++ b/learn/reif_examples.dj @@ -1,4 +1,4 @@ -# reif Cookbook +# reif Cookbook This tutorial shows some examples of using the predicates in [reif](/reif.html). Load lambda, dif, clpz, and reif into your toplevel to evaluate the examples in your toplevel. @@ -8,31 +8,30 @@ If you have an improvement (such as a better example or an explanation) to this ## Introduction -Here are predicates exported by reif. -``` +### Exported Predicates + +Here are predicates exported by reif: + +``` prolog :- module(reif, [if_/3, (=)/3, (',')/3, (;)/3, cond_t/3, dif/3, memberd_t/3, tfilter/3, tmember/2, tmember_t/3, tpartition/4]). ``` -The last argument of (=)/3, (,)/3, (;)/3, dif/3, or the predicates with principal functor ending in "_t" is the reified boolean value of the predicate. The _t -suffix of a functor name for a predicate expecting a reified boolean value is a convention, as is naming the corresponding argument or parameter T. -You may wish to follow that convention when writing your own predictes. - ### What is a reified boolean value? In prolog it means representing the truth of some expression or relation as a boolean value. Unlike many languages, the truthyness of a term like 'A < 10' can not be directly bound to a variable with an assignment. This is because terms have a different meaning in prolog that you should already be familiar with. - -``` +1111 +``` prolog ?- A is 112, C= (A<10). A = 112, C = (112<10). ?- ``` To make C bound to a boolean value with the built in (->): -``` +``` prolog ?- A is 2, ( A#<10 -> C=true;C=false), C, format("~s",["C holds"]). C holds A = 2, C = true. ?- A is 2000, ( A#<10 -> C=true;C=false), C, format("~s",["C holds"]). @@ -40,8 +39,9 @@ C holds A = 2, C = true. ?- ``` - _if from reif provides a better way to do the same. -``` +if_ from reif provides a better way to do the same, and you should consider using if_ unless you ahve a compelling reason to use -> . + +``` prolog ?- A #= 2,if_(A#<103,C=true,C=false),C,format("~s",["C Holds"]). C Holds A = 2, C = true. ?- @@ -49,7 +49,7 @@ C Holds A = 2, C = true. true holds (and false doesn't), even when bound to variables: -``` +``` prolog ?- X=true,X, format("foo",[]). foo X = true. ?- X=false,X, format("foo",[]). @@ -58,13 +58,12 @@ foo X = true. ``` oddly, there is no build in < notation in prolog for boolean values. -``` +``` prolog ?- false < true, true. error(type_error(evaluable,false/0),(is)/2). ?- ``` - Note that other Prolog modules may express a reified boolean value as 0 or 1 or choose some other representation instead of false and true. @@ -72,7 +71,7 @@ Note that other Prolog modules may express a reified boolean value as 0 or 1 or We will use tmember_t to demonstrate an example. T is bound to true when a condition holds, and false when it doesn't. -``` +``` prolog ?- tmember_t(#<(1),[1,2,3,4,6],T). T = true. ?- tmember_t(#<(100),[1,2,3,4,6],T). @@ -80,15 +79,22 @@ We will use tmember_t to demonstrate an example. T is bound to true when a con ?- ``` -The prefix of "t_" (tmember/2,tmember_t/3, tfilter, tpartition/4) in a predicate name indicates the first -argument will be a predicate that takes as as an argument a predicate (or partially applied predicate) taking additonal arguments, the last of which will +The prefix of t_ (tmember/2,tmember_t/3, tfilter, tpartition/4) in a predicate name indicates the first +argument is a predicate that takes as as an argument a predicate (or partially applied predicate) taking additonal arguments, the last of which will be a reified boolean value for whether the query holds. The naming convention for the parameters which are predicates is C_N, where C may convey some meaning about the arguments purpose, and the N indicates how many additional arguments are required by the predicate. -It is necessary useful to inspect the source of reif so you can see the information conveyed in the predicate and parameter names. -``` +A suffix of _t indicates the last parameter of a predicate is a reified boolean value. The last argument of the following are also reifed boolean values: +(=)/3, (,)/3, (;)/3, dif/3. + + +You may wish to follow that convention when writing your own predicates. + +It is useful to inspect the source of reif so you can see the information conveyed in the predicate and predicate parameter names. + +``` prolog :- meta_predicate(tfilter(2, ?, ?)). tfilter(_, [], []). @@ -100,14 +106,14 @@ truth value. For example, using dif/3 from reif, and applying one argument 3, gives a partially applied goal X_2 requiring two more arguments. -``` +``` prolog ?- X_2=dif(3), call(X_2,9,T). X_2 = dif(3), T = true. ?- ``` or more succinctly: -``` +``` prolog ?- call(dif(3),9,T). T = true. ?- @@ -118,7 +124,7 @@ some new prolog skills There is some code that you may find confusing, which shows a predicate expecting 2 arguments, but only one is provided: -``` +``` prolog if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs), ``` Fortunatley, you don't need to understand that mechanism to use the reif module. The C_2 parameter name gives you enough information about the predicate @@ -128,7 +134,7 @@ you must supply as an argument. You may be surprised when something like this works: -``` +``` prolog ?- call( tfilter,=(3),[3],X). X = [3]. ?- @@ -136,31 +142,30 @@ You may be surprised when something like this works: but this breaks. -``` +``` prolog ?- call( tfilter,#>(3),[3],X). error(existence_error(procedure,(#>)/3),(#>)/3). ?- ``` -What is happening is that reif has provided =/3, and that is what is being used in tfilter (not the usual =/2). +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): +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): -``` -pound_gt(X,Y,true):- X #>Y,!. -pound_gt(_,_,false). +``` prolog +pound_gt_t(X,Y,T) :- if_(Y #< X, T=true, T=false). -?- tfilter(pound_gt(3),[1,3],T). +?- tfilter(pound_gt_t(3),[1,3],T). T = [1]. ?- ``` -pound_gt is not very robust, using "!" for example. If you are writing predicates to use with reif, look at the implementation =/3 in reif. +If you are writing predicates to use with reif, look at the implementation (=)/3 in reif. You might wonder if you can write a predicate to relate a predicate with a reified value as the last parameter. -``` +``` prolog unreif_reif(P1, P2). ``` @@ -168,26 +173,26 @@ so that P1(A1, A2, ...AN) holds when P2(A1, A2, ..., AN, T) holds and T is the r [Probably not](https://github.com/mthom/scryer-prolog/discussions/2557), but you can probably learn something about writing reified versions of predicates by reading that discussion. -You can look at predicates like dif/3 or =/3 in [reif](/reif.html) to get ideas about writing predicates that include a reifed boolean value. +You can look at predicates like dif/3 or (=)/3 in [reif](/reif.html) to get ideas about writing predicates that include a reifed boolean value. ## memberd_t/3 Query holds if a single item 'c' is a member of a list. -``` +``` prolog ?- memberd_t(c,"branch free",true). true. ``` Query holds if single item is excluded from a list. Exclusion or inclusion is determined by the third argument. -``` +``` prolog ?- memberd_t(c,"branch free",false). true. ``` Query holds, and X is true if and only if a single item is included in the list. Note single quotes are normally not needed around atoms like 'c'. -``` +``` prolog ?- memberd_t(c,"branch free",X). X = true. ?- @@ -195,7 +200,7 @@ Query holds, and X is true if and only if a single item is included in the list. Query holds for Y in a member of the list and X is false or Y is not a member of the list and X is true. -``` +``` prolog ?- memberd_t(Y,[1,2,3],X). Y = 1, X = true ; Y = 2, X = true @@ -206,7 +211,7 @@ Query holds for Y in a member of the list and X is false or Y is not a member of Lists of length 2, where A is a member of exactly one of those lists. -``` +``` prolog length(L1,2),length(L2,2),memberd_t(A,L1,X), memberd_t(A,L2,Y), dif(X,Y). L1 = [A,_C], L2 = [_A,_B], X = true, Y = false, dif:dif(_A,A), dif:dif(_B,A) ; L1 = [_A,A], L2 = [_B,_C], X = true, Y = false, dif:dif(_A,A), dif:dif(_B,A), dif:dif(_C,A) @@ -239,7 +244,7 @@ if_1 calls predicate If_1, adding on the last argument the predicate expects, w if T then calls the predicate Then_0 otherwise, calls the predicate Else 0. -``` +``` prolog ?- if_( (X=3),(Y=4),(Z=5)), (X=4;X=3). X = 3, Y = 4 ; X = 4, Z = 5 @@ -251,7 +256,7 @@ In the above example, only Y or Z are instantiated variables, but not both. Example with a differrent comparison predicate. -``` +``` prolog greater_than_two(Y,true) :- Y #> 2. greater_than_two(Y,false) :- Y #=< 2. ?- if_(greater_than_two(3),X="works", X="fails"). @@ -266,7 +271,7 @@ tfilter/3 is a predicate for filtering lists. Again, worth reading the source, because it shows some prolog technique that may be new to you (unless you are a prolog expert already). -``` +``` prolog :- meta_predicate(tfilter(2, ?, ?)). tfilter(_, [], []). tfilter(C_2, [E|Es], Fs0) :- @@ -278,29 +283,29 @@ The meta_predicate directive is important. It specifies the first parameter to If your prolog system has -``` -#3 + ``` prolog + (#>)3 ```: -``` +``` prolog ?- tfilter(#>(10),[1,20,20], Xs). error(existence_error(procedure,(#>)/3),(#>)/3). ?- @@ -308,7 +313,7 @@ Oddly, scryer prolog 0.9.4-614 has ``` Relating a list, to a list without a certain element: -``` +``` prolog ?- tfilter(dif(10),[1,2,3,X],Es). X = 10, Es = [1,2,3] ; Es = [1,2,3,X], dif:dif(10,X). @@ -317,7 +322,7 @@ Relating a list, to a list without a certain element: See which predicates produce a non-empty list with tfilter. -``` +``` prolog ?- (X= =(3); X= #<(4); X= =(100) ), tfilter(X,[1,2,3,4,6],Y), Y\=[]. X = =(3), Y = [3] ; X = #<(4), Y = [6] @@ -325,41 +330,33 @@ See which predicates produce a non-empty list with tfilter. ?- ``` -## tmember/2 -Just like tfilter, tmember's first argument is a paritally applied 2-arity predicate: +## tmember/2 -``` -:- meta_predicate(tmember(2, ?)). -``` +Just like tfilter, tmember's first argument is a paritally applied 2-arity predicate. +It can be used to test for existance of an element for which the supplied predicate holds. -``` +``` prolog ?- tmember(=(3),[1,2,3,4,6]). true. -?- - -``` - - -It can be used to test for existance of an element for which the supplied predicate holds. - -``` ?- tmember(#<(1),[1,2,3,4,6]). true. ?- tmember(#<(12),[1,2,3,4,6]). false. ?- - ``` + + ## tmember_t + - tmembert can be used to test the existance or non-existance of an element of the list, - for which a predicate holds. + tmember_t can be used to test the existance or non-existance of an element of the list, + for which a predicate holds. -``` +``` prolog ?- tmember_t(#<(1),[1,2,3,4,6],T). T = true. ?- tmember_t(#<(100),[1,2,3,4,6],T). @@ -367,17 +364,17 @@ It can be used to test for existance of an element for which the supplied predic ?- ``` - - ## tpartition/4 + +## tparttition/4 Partition a list based on a predicate requiring two more arguments. - ``` + ``` prolog :- meta_predicate(tpartition(2, ?, ?, ?)). ``` Partition a list based on larger than 4: - ``` + ``` prolog ?- tpartition(#<(4),[1,2,3,4,5,6,3,4,5],A,B). A = [5,6,5], B = [1,2,3,4,3,4]. ?- @@ -385,7 +382,7 @@ Partition a list based on a predicate requiring two more arguments. Find Z, for which #<(Z) partions [1,2,4,5] into [4,5], and [1,2]: -``` +``` prolog ?- tpartition(#<(Z),[1,2,4,5],[4,5],[1,2]), indomain(Z). Z = 2 ; Z = 3 @@ -404,13 +401,13 @@ The first argument is a predicate requiring one more argument, which is the rei The prolog system provides some help here. The prolog system uses =/3 in this example, because =/3 wouldn't match. -``` +``` prolog ?- if_(X=8, Z=3, M=4). ``` or -``` +``` prolog ?- if_(X#<8, Z=3, M=4). M = 4, clpz:(X in 8..sup), clpz:(X+1#=_A), clpz:(_A in 9..sup) ; Z = 3, clpz:(X in inf..7), clpz:(X+1#=_A), clpz:(_A in inf..8). @@ -420,7 +417,7 @@ or Attemtping to use a 0-ary predicate fails: -``` +``` prolog ?- Y=true, if_(Y, Z=3, M=4). error(existence_error(procedure,true/1),true/1). ?- @@ -437,17 +434,21 @@ Which you can easily work around with: Seems to be an if construct without an else. -``` +``` prolog ?- cond_t(A=B,format("A is B",[]), true),A=west,B=west. A is B A = west, B = west ; false. ``` -``` +``` prolog ?- cond_t(A=B,format("A is not B",[]), false),A=wild,B=one. A is not B A = wild, B = one. ``` ## ,/3 and ;/3 Todo: Explain how ,/3 and ;/3 are to be used, and how they are used internally withing reif. - \ No newline at end of file + +# Motiviation for Using reif + +Todo: add some examples compared to using list or builtin predicates. + From 0d5dd009cd1ada6c6491035f80dfc3add4775cbf Mon Sep 17 00:00:00 2001 From: Doug Date: Sun, 5 Oct 2025 15:58:21 -0700 Subject: [PATCH 07/11] edits --- learn/reif_examples.dj | 59 ++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/learn/reif_examples.dj b/learn/reif_examples.dj index 86800530d..d0f160e80 100644 --- a/learn/reif_examples.dj +++ b/learn/reif_examples.dj @@ -23,7 +23,7 @@ Here are predicates exported by reif: In prolog it means representing the truth of some expression or relation as a boolean value. Unlike many languages, the truthyness of a term like 'A < 10' can not be directly bound to a variable with an assignment. This is because terms have a different meaning in prolog that you should already be familiar with. -1111 + ``` prolog ?- A is 112, C= (A<10). A = 112, C = (112<10). @@ -57,14 +57,15 @@ foo X = true. ?- ``` -oddly, there is no build in < notation in prolog for boolean values. +Oddly, there is no build in < operator in prolog for boolean values: + ``` prolog ?- false < true, true. error(type_error(evaluable,false/0),(is)/2). ?- ``` -Note that other Prolog modules may express a reified boolean value as 0 or 1 or choose some other representation instead of false and true. +Note that other Prolog modules (like clp(z)) may express a reified boolean value as 0 or 1 or choose some other representation instead of false and true. ### Naming Conventions in reif @@ -151,7 +152,7 @@ but this breaks. 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): +A workaround is to define a three-arity predicate to do the comparison (it could be (#>)/3, but I choose pound\_gt\_t): ``` prolog pound_gt_t(X,Y,T) :- if_(Y #< X, T=true, T=false). @@ -190,40 +191,42 @@ Query holds if single item is excluded from a list. Exclusion or inclusion is d true. ``` -Query holds, and X is true if and only if a single item is included in the list. Note single quotes are normally not needed around atoms like 'c'. +Query holds, and T is true if and only if a single item is included in the list. ``` prolog -?- memberd_t(c,"branch free",X). - X = true. +?- memberd_t(c,"branch free",T). + T = true. ?- ``` -Query holds for Y in a member of the list and X is false or Y is not a member of the list and X is true. +Query holds for Y in a member of the list and T is false or Y is not a member of the list and T is true. ``` prolog -?- memberd_t(Y,[1,2,3],X). - Y = 1, X = true -; Y = 2, X = true -; Y = 3, X = true -; X = false, dif:dif(1,Y), dif:dif(2,Y), dif:dif(3,Y). +?- memberd_t(Y,[1,2,3],T). + Y = 1, T = true +; Y = 2, T = true +; Y = 3, T = true +; T = false, dif:dif(1,Y), dif:dif(2,Y), dif:dif(3,Y). ?- + ``` Lists of length 2, where A is a member of exactly one of those lists. ``` prolog -length(L1,2),length(L2,2),memberd_t(A,L1,X), memberd_t(A,L2,Y), dif(X,Y). - L1 = [A,_C], L2 = [_A,_B], X = true, Y = false, dif:dif(_A,A), dif:dif(_B,A) -; L1 = [_A,A], L2 = [_B,_C], X = true, Y = false, dif:dif(_A,A), dif:dif(_B,A), dif:dif(_C,A) -; L1 = [_A,_B], L2 = [A,_C], X = false, Y = true, dif:dif(_A,A), dif:dif(_B,A) -; L1 = [_A,_B], L2 = [_C,A], X = false, Y = true, dif:dif(_A,A), dif:dif(_B,A), dif:dif(_C,A) +?- length(L1,2),length(L2,2),memberd_t(A,L1,TX), memberd_t(A,L2,TY), dif(TX,TY). + L1 = [A,_C], L2 = [_A,_B], TX = true, TY = false, dif:dif(_A,A), dif:dif(_B,A) +; L1 = [_A,A], L2 = [_B,_C], TX = true, TY = false, dif:dif(_A,A), dif:dif(_B,A), dif:dif(_C,A) +; L1 = [_A,_B], L2 = [A,_C], TX = false, TY = true, dif:dif(_A,A), dif:dif(_B,A) +; L1 = [_A,_B], L2 = [_C,A], TX = false, TY = true, dif:dif(_A,A), dif:dif(_B,A), dif:dif(_C,A) ; false. -?- +?- ``` ## (=)(A,B,T). -reif introdces =/3, which holds if and only if the first two arguments are equal, and the third argument T is true or the first two arguments are not equal the the third argument is false. T is the 'reified' truth value of A. +reif introdces (=)/3, which holds if and only if the first two arguments are equal, and the third argument T is true or the first two arguments are not equal the the third argument is false. +T is the reified truth value of =(A,B). ``` prolog ?- (reif:(=)(1,2,false). @@ -345,14 +348,8 @@ It can be used to test for existance of an element for which the supplied predic false. ?- ``` - - - - ## tmember_t - - tmember_t can be used to test the existance or non-existance of an element of the list, for which a predicate holds. @@ -365,7 +362,7 @@ It can be used to test for existance of an element for which the supplied predic ``` -## tparttition/4 +## tpartition/4 Partition a list based on a predicate requiring two more arguments. @@ -395,14 +392,14 @@ Find Z, for which #<(Z) partions [1,2,4,5] into [4,5], and [1,2]: [if_/3](https://www.metalevel.at/prolog/metapredicates) "correctly commits to one of two alternatives when admissable …". - - The first argument is a predicate requiring one more argument, which is the reified truth value of a comparsion . -The prolog system provides some help here. The prolog system uses =/3 in this example, because =/3 wouldn't match. +The prolog system provides some help here. The prolog system uses (=)/3 in this example, because (=)/3 wouldn't match. ``` prolog -?- if_(X=8, Z=3, M=4). +?- if_(X=8, Z=3,M=4). + X = 8, Z = 3 +; M = 4, dif:dif(X,8). ``` or From f5db942d96df1c0a189e8cedd9e095217ac015dd Mon Sep 17 00:00:00 2001 From: Doug Date: Sun, 5 Oct 2025 16:08:49 -0700 Subject: [PATCH 08/11] edits --- learn/reif_examples.dj | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/learn/reif_examples.dj b/learn/reif_examples.dj index d0f160e80..0221af8bb 100644 --- a/learn/reif_examples.dj +++ b/learn/reif_examples.dj @@ -306,7 +306,7 @@ Oddly, scryer prolog 0.9.4-614 has ``` prolog (#>)3 - ```: + ``` ``` prolog ?- tfilter(#>(10),[1,20,20], Xs). @@ -364,14 +364,16 @@ It can be used to test for existance of an element for which the supplied predic ## tpartition/4 -Partition a list based on a predicate requiring two more arguments. +Partition a list based on a predicate requiring two more arguments: + + +``` prolog +:- meta_predicate(tpartition(2, ?, ?, ?)). +``` - ``` prolog - :- meta_predicate(tpartition(2, ?, ?, ?)). - ``` Partition a list based on larger than 4: - ``` prolog +``` prolog ?- tpartition(#<(4),[1,2,3,4,5,6,3,4,5],A,B). A = [5,6,5], B = [1,2,3,4,3,4]. ?- From c23bbf0a50f2bba4568d2298cf87081d80c3ea97 Mon Sep 17 00:00:00 2001 From: Doug Date: Sun, 5 Oct 2025 16:23:58 -0700 Subject: [PATCH 09/11] edits --- learn/reif_examples.dj | 1 + 1 file changed, 1 insertion(+) diff --git a/learn/reif_examples.dj b/learn/reif_examples.dj index 0221af8bb..5021cf1f6 100644 --- a/learn/reif_examples.dj +++ b/learn/reif_examples.dj @@ -316,6 +316,7 @@ Oddly, scryer prolog 0.9.4-614 has ``` Relating a list, to a list without a certain element: + ``` prolog ?- tfilter(dif(10),[1,2,3,X],Es). X = 10, Es = [1,2,3] From 42bc69278df2e6df2ae5a0239c050c278d3650e6 Mon Sep 17 00:00:00 2001 From: Doug Date: Sun, 5 Oct 2025 16:57:16 -0700 Subject: [PATCH 10/11] edits --- learn/reif_examples.dj | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/learn/reif_examples.dj b/learn/reif_examples.dj index 5021cf1f6..5b7b78afe 100644 --- a/learn/reif_examples.dj +++ b/learn/reif_examples.dj @@ -223,10 +223,12 @@ Lists of length 2, where A is a member of exactly one of those lists. ?- ``` -## (=)(A,B,T). +## (=)/3 -reif introdces (=)/3, which holds if and only if the first two arguments are equal, and the third argument T is true or the first two arguments are not equal the the third argument is false. -T is the reified truth value of =(A,B). +reif introdces (=)/3, which holds if and only if the first two arguments + X and Y are equal, and the third argument T is true or X and Y not equal and T is false. + +T is the reified truth value of =(X,Y). ``` prolog ?- (reif:(=)(1,2,false). @@ -243,9 +245,8 @@ You may find it useful to write predicates where the last argument is a boolean ## 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. +The first argument to if_/3 is a predicate expecting one argument, which is a boolean value T. Read the definition in reif.pl for the meaning of the +remaining arguments. ``` prolog ?- if_( (X=3),(Y=4),(Z=5)), (X=4;X=3). @@ -260,11 +261,10 @@ In the above example, only Y or Z are instantiated variables, but not both. Example with a differrent comparison predicate. ``` prolog -greater_than_two(Y,true) :- Y #> 2. -greater_than_two(Y,false) :- Y #=< 2. +greater_than_two(Y, true) :- Y #> 2. + ?- if_(greater_than_two(3),X="works", X="fails"). X = "works". -?- ``` ## tfilter/3 @@ -282,7 +282,6 @@ tfilter(C_2, [E|Es], Fs0) :- tfilter(C_2, Es, Fs). ``` -The meta_predicate directive is important. It specifies the first parameter to tfilter is a predicate needing two more arguments. The first required argument is the value to be compared from the list, and the second is the reified result of the comparison (true, or false). If your prolog system has @@ -397,7 +396,7 @@ Find Z, for which #<(Z) partions [1,2,4,5] into [4,5], and [1,2]: The first argument is a predicate requiring one more argument, which is the reified truth value of a comparsion . -The prolog system provides some help here. The prolog system uses (=)/3 in this example, because (=)/3 wouldn't match. +The prolog system provides some help here. The prolog system uses (=)/3 in this example for the comparison X=8. ``` prolog ?- if_(X=8, Z=3,M=4). From 2e1c1804dd5574d18061796527ec71663d70258e Mon Sep 17 00:00:00 2001 From: Doug Date: Sun, 5 Oct 2025 17:00:19 -0700 Subject: [PATCH 11/11] edits --- learn/reif_examples.dj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/learn/reif_examples.dj b/learn/reif_examples.dj index 5b7b78afe..79ef0896a 100644 --- a/learn/reif_examples.dj +++ b/learn/reif_examples.dj @@ -394,7 +394,7 @@ Find Z, for which #<(Z) partions [1,2,4,5] into [4,5], and [1,2]: [if_/3](https://www.metalevel.at/prolog/metapredicates) "correctly commits to one of two alternatives when admissable …". -The first argument is a predicate requiring one more argument, which is the reified truth value of a comparsion . +The first argument is a predicate requiring one more argument, which is the reified truth value of a comparison. The prolog system provides some help here. The prolog system uses (=)/3 in this example for the comparison X=8.