I think if you take a day or so to understand unification and backtracking, you'll be ready to implement. You don't need to be a Prolog expert to implement Prolog; after all, the inventors of Prolog weren't before they invented it. I would say, make sure you understand unification and backtracking. This is probably a day or two of messing around with Prolog.
If you really want to get into the implementation details, Warren's Abstract Machine: A Tutorial Reconstruction is really good. There's an offhand remark at the start of Compiling with Continuations about how if you were to implement Prolog with continuation-passing style that you would need two continuations. This is by analogy to the two stacks WAM uses: you need one for the call stack and one for the trail, which is the way it keeps track of the last choice point or location to backtrack to in order to resume the search. You don't need to get too deep into unification to understand the necessity of this; a simple query like member(X, [1,2,3]), X mod 2 =:= 0
is probably enough to illustrate it. But the point is, if you are more comfortable with continuations than stacks, there's an alternative there. I agree that miniKanren is probably a great place to start. I haven't looked at it so I'm not sure how it manages this.
I think the key point is to really understand unification. That won't take you as long as you are afraid; most Prolog tutorials have a section on unification writ large. Until you know what to expect though it will be hard to know whether you have implemented it correctly. That doesn't mean you need to be a Prolog expert. You might want to understand the occurs check and why it is usually omitted. But again, this is not like a great depth of knowledge of Prolog you need to obtain before you get into it.
> You would have to solve a question of persistence, since assert(fact) doesn't persist a new fact, and it only stays in memory as long as the program runs. On the other hand, creating persistent layer is more straight-forward: you could just write facts to a file the same way they are passed to assert. Or maybe, dump the database to a file every now and then.
I have a feeling you're really going to enjoy library(persistency).
You are reading it correctly more or less and the other comment by /u/cathray explains it well enough.
But you might be missing something. Basically, yes, this says, "succeed when A is a variable" but additionally, it says:
"Succeed when A is a variable that can be bound to 0 or to 1".
Withtout any context it is just wild guesses, but this could be useful when you try to model boolean values or maybe constraints or why not both.
Using a bit more modern notation (not not
but \+
instead), here is what I get for SWI-Prolog:
$ swipl Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.13-31-g8782b0084) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- [user]. |: p(A) :- + + A = 0, + + A = 1. |: ^D% user://1 compiled 0.00 sec, 1 clauses true.
?- p(1). false.
?- p(X). true.
?- dif(X, 0), p(X). false.
?- dif(X, -1), p(X). dif(X, -1).
?- use_module(library(clpfd)). true.
?- X in 0..1, p(X). X in 0..1.
?- X in 0..10, p(X). X in 0..10.
?- X #> 1, p(X). false.
?- X #> 1, var(X). X in 2..sup.
The last two queries show you an example where var(X)
succeeds but p(X)
fails: X is still a variable, but it cannot be either 0 nor one! This is the same as with the dif
constraint above.
But why this predicate is defined like this is still open to speculation since we are lacking context.
Go to the SWI-Prolog website maybe? Did you try googling "SWI-Prolog"?
BTW, forget about these "tutorials". They just copy the stuff from the official website without adding too much useful stuff. Go ahead and read the "HOWTO collection" linked in the abstract here:
http://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/http.html%27)
(Using SWI-prolog) maplist can do part of this.
?- maplist(succ, [1,2,3,4], Results). Results = [2, 3, 4, 5].
But instead of succ, it could be your relation that takes a manager and returns [Manager, [Subordinate, Subordinate, ...]. If you haven't written that yet, you can use findall/3 to do much of that.
Have you tried the following: http://www.swi-prolog.org/FAQ/GnuEmacs.html
I am not sure if makes a difference as I have not used xpce but I tried using the operator in my emacs and it didnt seem to do anything weird.
No problem. It can be handy to keep a list of operator precedence handy; here's SWI-Prolog's. Notice that ,
binds more strongly than ->
(it has a lower precedence number).
Constraint logic programming (clp) allows you to define the variables and ranges of those variables (the 8 queens and positions on a grid) along with constraints, that is defined rules which would invalidate part of that range for the variables.
Then prolog does the rest for you. :) (usually). Here's SWI-Prolog's manual on finite domain clp.
(I've been intentionally vague because you asked for hints, but if your google-fu is high, you'll be able to find examples of this problem using clp. Though figuring it out on your own is always fun as well! )
This should be a good chapter to read up on, there are some examples later down.
It's possible in specific libraries of prolog, but not standard prolog.
Yes, perfectly right. Consider for example the SWI-Prolog homepage, which is entirely hosted by SWI-Prolog itself.
SWI-Prolog comes with a particularly strong set of libraries to implement HTTP services and to communicate with remote Prolog engines (search for pengines).
JSON syntax is also supported.
Um okay dude this is literally the last part of my homework chill out.
This is literally like %3 of the homework, I've been googling for the past two days before I posted here so don't call me lazy. I did google it but I didn't understand it. Seeing as how I just started learning this I don't see how that makes me "lazy".
If you're wondering this is the website I found, since it's off of the program we're using to compile I figured that would be the one I should read.
This is my first scripting language, I just started programming all together not that long ago. I'm sorry I don't mean to yell at you, it's just frustrating that you're calling me lazy when I go through all that work to try to find an answer and then have to post on the internet for help and get called lazy.
I think I see what you want. Here's what I would do:
Getting the client times is just client(ID, Time), where the list of available client times is stored in Time. You do the exact same for property times, except, since you have a list of ids, you need to do it element by element. Write a recursive function to do that for you. See this link for help with recursion if you've never worked with it before.
You can also try the maplist function to get the property times, which I think might return a list of lists. You can then flatten the list if you want all times in a single list.
I too have never used this. So I queried "freeze example" on comp.lang.prolog and came up with - (https://groups.google.com/group/comp.lang.prolog/browse_thread/thread/73655b88993c11b7/53768415bee6e727?lnk=gst&q=freeze+example)
there are some good examples in there (from 1990!).
From memory you have to define the higher order predicate as a meta predicate in the module it is defined. This allows you to use other modeled predicates.
You might also need to prefix the module name when calling e.g.: higher_order(module_name:callee, ...)
I've done it swi-prolog and here are the relevant docs. http://www.swi-prolog.org/pldoc/doc_for?object=(meta_predicate)/1
I'm on my phone otherwise would give an example, but that is a good place to start.
Another way to approach this class of problems is to realize that all of them have in common this: you look into pairs of elements in such a way that one element is chosen from the input sequence uniquely, and another one is the one you have computed so far. This common thing is known as "reduction" or "folding", and different programming languages have baked-in way to automate this. For instance, SWI Prolog has http://www.swi-prolog.org/pldoc/man?predicate=foldl/4 .
Using this predicate, your work will be reduced to only defining such a predicate that given an element of a sequence and the minimal value computed so far will compute the minimal of them two. This is not as trivial as it may sound though, especially if you are trying to compare things that aren't comparable, or it is not known whether they are comparable (uninstantiated variables), what exactly you want to do about the edge cases will depend on a specific task you want to apply this to. Since it is just a learning exercise, I think, it's OK to just assume all elements of the list are numbers, but you need to keep in mind the limitations.
You need to tell Prolog to evaluate the N - 1
using <code>is/2</code>. Like this:
element_at(X,[H|T],N) :- N1 is N - 1, element_at(X,T,N1).
I see. <code>.</code> is registered as an operator in SWI-Prolog's regular mode to support dict lookup, but it's not an operator in standard Prolog.
Yes. For example, here's a rule that will filter down to only include the numbers greater than 5:
gt_five([], []). gt_five([ A | As], [ A | Bs]) :- A > 5, gt_five(As, Bs). gt_five([ A | As], Bs) :- A =< 5, gt_five(As, Bs).
You could adapt that to instead build a list that only contains the values that satisfy your is_factor
predicate.
Or, in SWI-Prolog, there are some builtins that help you do this with metaprogramming. <code>include/3</code> can be used in a way that's similar to filter
from functional programming. You could try this:
build_list(12, L), include(is_factor(12), L, RL).
... except that won't work. include/3
appends the values from the source list to the goal that you provide. So that will effectively evaluate all of these:
is_factor(12, 1) is_factor(12, 2) is_factor(12, 3) is_factor(12, 4) ...
But you want it to evaluate:
is_factor(1, 12) is_factor(2, 12) is_factor(3, 12) is_factor(4, 12) ...
The easiest way to handle that is to just flip the parameters to is_factor
. If you don't want to do that, you'd need to create a helper rule:
is_factor_flip(N1, N) :- is_factor(N, N1).
The examples page look at the 1st box and the 3rd box for example uses of a multi-head rule. Hope this helps.
This can be a bit complicated if you are just learning prolog though, so if this is just confusing feel free to ignore for now.
See the SWI-Prolog documentation of library(clpfd)
:
http://www.swi-prolog.org/man/clpfd.html
This shows that for truncated integer division, you should use (//)/2
. For example, write A // B #= 2
.
Currently, you are using /
instead of //
.
A closely related, if not identical issue, was recently discussed on the SWI mailing list, please see the forum thread for more information.
Does the workaround that is explained in this post work for you?
http://www.swi-prolog.org/pldoc/doc_for?object=read_util:read_file_to_string/3 ?
Alternatively, you can use read_line_to_string/2 http://www.swi-prolog.org/pldoc/doc_for?object=read_util:read_line_to_string/2
Out of curiosity, what are you working on?
My reply assumes you're using SWI-Prolog. But I'm sure there are ways to achieve your desired result in any implementation.
If you really wanted to add facts to your main Prolog environment, i.e., so that they would be available when you ran $ swipl -g 'fact(X,Y);halt'
, you can load the desired database into you user initialization file, e.g., by adding
:- consult('path/to/databse.pl').
But that will pollute your runtime environment with those facts and potentially impact any other programs you run via swipl
. A slightly more cautious approach would be to import the database as a module, so you can control exactly which predicates are made openly available to the system. Or, you could also refrain from exporting predicates from the database file, so that the facts would only be available by using the module:prediate/n
idiom; that would provide a bit of encapsulation. Then your command line queries would look like:
$ swipl -g 'database:fact(X,Y); halt'
.
But, take note, if you just query a fact this way, I don't think you'll get any output at all. swipl
will run the goal fact(X,Y)
and if it succeeds, it will drop you you into the interactive top level; if it fails, it will call halt
and terminate. Unless fact/2
were actually a rule that included instructions for what sort of output to produce.
However, I'm not sure when it would be useful to use the the Prolog toplevel just to query a custom database of facts. I would probably make a little PrologScript program to query the database and output answers in a useful fashion.
I hope that helps! Please follow up if you have additional questions or to clarify if I misunderstood your question :)
I learnt a lot with Dennis Merritt's Building Expert Systems in Prolog: www.inf.fu-berlin.de/lehre/SS08/KI/merritt.pdf
Also, for non logic related development with prolog Jan Wielemaker's thesis is fairly good www.swi-prolog.org/download/publications/jan-phd.pdf
And of course, SWI-Prolog publication area is a must check: http://www.swi-prolog.org/Publications.html)
Actually I really appreciated Get Programming with Haskell by Will Kurt as an intro book but that wasn't my point. I'm just saying I wish there were more modern and in depth prolog books, for multiple reasons.
In the code snippet you show, the only thing that wouldn't "work" is the X^intr(Y)
in the body of the first of the two rules. The X^Y
in the head should "work" if ^
is defined as an operator. Here is what I see:
$ swipl Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.15-10-g6718ecfeb) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- current_op(Precedence, Type, ^). Precedence = 200, Type = xfy.
?- display(a^b). ^(a,b) true.
To show that you can indeed have X^Y
in the head:
?- [user].
|: intr(X^Y) :- format("Got intr(~w^~w)
~n", [X, Y]).
|: ^D% user://1 compiled 0.02 sec, 1 clauses
true.
?- intr(a^b).
Got intr(a^b)
true.
But I don't understand what you want the body of that rule to do. I also couldn't easily define a callable ^/2
. Here is what I tried and what I got:
?- [user].
|: X^Y :- format("Evaluating ~w^~w
as a goal~n", [X, Y]).
|: ^D% user://2 compiled 0.02 sec, 1 clauses
true. % <---- seems to work? but not really
?- a^b. ERROR: Unknown procedure: b/0 (DWIM could not correct goal) ?- X^B. ERROR: Unknown procedure: '$toplevel':(^)/2 ERROR: ^/2 can only appear as the 2nd argument of setof/3 and bagof/3 ERROR: In: ERROR: [10] '$toplevel':_12658^(user:_12666) ERROR: [9] <user> Exception: (10) _11996^(user:_11998) ? creep
So, I found a bit of time. I allowed myself the liberty to model your problem a bit differently. I just used one variable per person, and the domain of each is the available time slots. I cheated a bit in the sense that I just typed it in instead of reading it from a file. I also manually enumerated the possible groupings, of which there are only three (I mean that there are only three ways to split 4 people in two groups of two people each). Here is the code, in a file called scheduler.pl
.
:- use_module(library(clpfd)). schedule([P1,P2,P3,P4]) :- P1 in 1\/2\/4\/5, P2 in 1\/2\/3, P3 in 6, P4 in 1\/4\/6, ( P1 #= P2, P3 #= P4 ; P1 #= P3, P2 #= P4 ; P1 #= P4, P2 #= P3 ).
Here I load it and run it (also time it):
$ swipl Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.15-10-g6718ecfeb) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details. For online help and background, visit http://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word). ?- [scheduler]. true. ?- time(schedule(S)). % 590 inferences, 0.000 CPU in 0.000 seconds (99% CPU, 1204050 Lips) S = [_5656, _5656, 6, 6], _5656 in 1..2 ; % 174 inferences, 0.000 CPU in 0.000 seconds (99% CPU, 568711 Lips) false.
As you see, you also get the time slots (not sure how to get those automatically from your attempt).
I think this should give you a push in the right direction. If you have questions about the technical bits, for example how to read in the data instead of hard-coding it, or how to make meaningful splits for the groups, feel free to ask.
EDIT: You might hope that u/zmonx sees your question. I suspect they might have something actually clever to say about this. For example, I am quite sure that this disjunction at the end is not the clean way to model this, but I am running out of time now.
So, I found a bit of time. I allowed myself the liberty to model your problem a bit differently. I just used one variable per person, and the domain of each is the available time slots. I cheated a bit in the sense that I just typed it in instead of reading it from a file. I also manually enumerated the possible groupings, of which there are only two (I mean that there are only two ways to split 4 people in two groups of two people each). Here is the code, in a file called scheduler.pl
.
:- use_module(library(clpfd)).
schedule([P1,P2,P3,P4]) :- P1 in 1\/2\/4\/5, P2 in 1\/2\/3, P3 in 6, P4 in 1\/4\/6, ( P1 #= P2, P3 #= P4 ; P1 #= P3, P2 #= P4 ).
Here I load it and run it (also time it):
$ swipl Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.15-10-g6718ecfeb) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- [scheduler]. true.
?- time(schedule(S)). % 610 inferences, 0.000 CPU in 0.000 seconds (99% CPU, 4184560 Lips) S = [_3682, _3682, 6, 6], _3682 in 1..2 ; % 19 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 231208 Lips) false.
I think this should give you a push in the right direction. If you have questions about the technical bits, for example how to read in the data instead of hard-coding it, or how to make meaningful splits for the groups, feel free to ask.
Your logic is correct, but you botched the implementation. When you compiled this, you should have seen 2 warnings. Here is what I get:
$ cat alive.pl
scientist(boyle, 1627, 1691).
scientist(newton, 1642, 1727).
alive_after(X, Year) :- scientist(A, B, C), B < Year.
alive_before(X, Year) :- scientist(A, B, C), C > Year.
alive_during(X, Year) :- alive_after(X, Year), alive_before(X, Year).
$ swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.11-5-g06c5c9b7d-DIRTY)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- [alive].
Warning: .../alive.pl:4:
Warning: Singleton variables: [X,A,C]
Warning: .../alive.pl:6:
Warning: Singleton variables: [X,A,B]
true.
If you get rid of all the warnings your program will work as expected. After I fix the warnings (by editing alive.pl
, no need to restart Prolog, just edit, save, run make
), I get:
?- make.
% Updating index for library .../lib/swipl/library/
% .../alive compiled 0.00 sec, 0 clauses
true.
?- alive_during(X, 500).
false.
?- alive_during(X, 1700).
X = newton.
?- alive_during(X, 1650).
X = boyle ;
X = newton.
?- alive_during(X, 1630).
X = boyle ;
false.
Hint: in alive_after/2
, what is the first argumen? What should be the first argument of the call to scientist/3
inside the body of alive_after/2
?
It should give the correct answer the first time. The bug is when you try to backtrack across it.
After it runs the first time, press ;
or the space bar to trigger a backtrack, then witness the crash:
$ swipl Welcome to SWI-Prolog (threaded, 64 bits, version 8.0.3) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- [user]. |: range(Start, Stop, Range) :- |: Start < Stop, |: insecureRange(Start, Stop, Range). |: |: insecureRange(Stop, Stop, []). |: insecureRange(Start, Stop, [Start | Starts]) :- |: NStart is Start + 1, |: insecureRange(NStart, Stop, Starts). |: ^D% user://1 compiled 0.00 sec, 3 clauses true.
?- range(0, 3, R). R = [0, 1, 2] ; Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack Could not reenable global-stack ERROR: Out of global-stack. ERROR: No room for exception term. Aborting.
For timing, Prolog has time/1
:
?- time(findall(X, between(0, 1000000, X), Xs)). % 2,000,014 inferences, 0.423 CPU in 0.446 seconds (95% CPU, 4725094 Lips) Xs = [0, 1, 2, 3, 4, 5, 6, 7, 8|...].
For the swi-prolog I put the code in myfile.pl
and ran this:
$swipl myfile.pl
Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.17)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).
Cannot read termcap database;
using dumb terminal settings.
?- time(test).
and the python program I tested in an ipython console like this:
$ipython
Python 3.6.5 (default, Jun 17 2018, 12:13:06)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.0.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: normal_leap_year = lambda Y: 0 == Y%4
...: exception = lambda Y: 0==Y%100
...: exception_to_exception = lambda Y: (Y%900) in (200,600)
...: leap_year = lambda Y: (normal_leap_year(Y) and not exception(Y)) or (norm
...: al_leap_year(Y) and exception(Y) and exception_to_exception(Y))
...: leaps = lambda Y1, Y2: len(list(filter(leap_year, range(Y1, Y2))))
...: def test():
...: return (
...: leaps(2019, 2020) == 0
...: and leaps(1900, 1901) == 0
...: and leaps(2000, 2001) == 1
...: and leaps(2800, 2801) == 0
...: and leaps(123456, 123456) == 0
...: and leaps(1234, 5678) == 1077
...: and leaps(123456, 7891011) == 1881475
...: )
...:
In [2]: %time test()
In [3]: %timeit test()
Note on python version: lines 2 and 3 are slightly different ways of measuring speed but they came out the same in this instance.
As far as I can tell, both interpreters have analyzed the relevant code before the test is timed. Feedback very welcome though, thanks!
| actually does do or, but it’s legacy notation (though still kinda popular in DCGs?), and most code would use ; instead.
But it will mean OR when composing goals, not as part of list notation.
This is a more complex control flow than exceptions were designed for. Continuations may line up more naturally with the kind of control flow you are imagining.
http://www.swi-prolog.org/download/publications/iclp2013.pdf
If you specifically want to find lists of "u"
strings, you can continually move the first element of the String
argument to the Leftover
list and check that it is in fact a "u"
. This fails as soon as it finds a different entry. After you have reached the end of the list, all elements are now in Leftover
, and you can just return its length:
uA(L, [], Ls) :- length(Ls, L). uA(L, [S|Strs], Ls) :- S = "u", uA(L, Strs, [S|Ls]).
You can also "cheat" a bit by using the <code>forall/2</code> predicate to do the iteration for you:
uA2(L, Strs, _) :- forall(member(Str, Strs), Str = "u"), length(Strs, L).
If To check if all elements of String
are equal but you do not care about their actual value, you can just check if all consecutive pairs are equal:
uA3(L, [], Ls) :- length(Ls, L). uA3(L, [S], Ls) :- uA3(L, [], [S|Ls]). uA3(L, [A,B|Strs], Ls) :- A = B, uA3(L, [B|Strs], [A|Ls]).
You can also compare the first element to all the other ones, I use forall/2
again:
# in the empty input all elements are the same and the length is 0 uA4(0, [], _).
# if there is at least on element, we make sure that all elements # of the rest of the list are the same and hte length is one more # than the length of the rest uA4(L, [S|Strs], _) :- forall(member(T, Strs), S = T), length(Strs, L1), succ(L1, L).
Yes, that's the approach you'd want to take.
Consider that you define checker
like this:
checker(X) :- ?.
At the topmost level, X
would be bound to and(propositional(X), true)
. You need a way to see what you got in X
and take appropriate action.
I'll refer you again to the type test predicates. They have most of what you need. The only other thing you'll need are the predicates to break down a compound term.
I don't want to just give away the solution, but I'd be happy to answer specific questions as they come up. If you're not sure where to start, it might be worthwhile to just play around with those type test predicates and term manipulation predicates. Play around in the Prolog REPL and build up an intuition about how the pieces work.
SWI manual page on finite domains has a solver written as an example: http://www.swi-prolog.org/pldoc/man?section=clpfd (towards the bottom).
You could start by benchmarking it against your problem. If it outperforms your solution, compare SWI implementation to yours piece-wise. This will probably give you an insight as to where your code is doing something that could be improved.
Oh, I see, well... one way to go about it would be to inspect the stack of the program, and prevent infinite recursion. Here's some info on SWI: http://www.swi-prolog.org/pldoc/man?section=manipstack . Another way is to maintain some other global state in which to register the fact that some predicate was already entered. Another way is to have an extra argument, essentially capturing this part of the state. Yet another way is to have a special helper predicate:
edge_helper(1, 2). edge_helper(2, 3).
edge(X, Y) :- edge_helper(X, Y) ; edge_helper(Y, X).
%% ?- findall([X, Y], edge(X, Y), Edges). %% Edges = [[1, 2], [2, 3], [2, 1], [3, 2]].
This particular gem found its way into Michael T. Richter's pack evil
. You can see it here:
http://www.swi-prolog.org/pack/file_details/evil/prolog/evil.pl
I think that in the pack, it is wrongfully attributed to Jan Wielemaker. I am too lazy to do the footwork but I suspect it was contributed by Ulrich Neumerkel himself, while showing off his library(pio)
. If I remember correctly, he withdrew his contributions when SWI-Prolog stopped being "free" and became "open source". All "pure input" code is now written by Jan Wielemaker.
Michael T. Richer, on the other hand, wrote a somewhat popular article once:
"Why I no Longer contribute to StackOverflow". Due to bitrot you can only find reflections of it these days; but the fact that there are reflections tells me it did have a bit of impact.
Neat! Looks like write_term's cycles(true) option: http://www.swi-prolog.org/pldoc/doc_for?object=write_term/2 If only there was a way to write all parts of a term that way!
Making the sharing semantics explicit definitely makes sense. We could probably even define a predicate that transforms implicitly-sharing datatypes into explicitly-sharing datatypes...
I think you're discounting what I'm saying. first_word
is wrong no matter what you name it because you're breaking your grammar into pieces in the wrong places. And as for mans/men, doing it the right way is as much work as doing it the wrong way. Making the excuse for doing it wrong is more effort than doing it the right way.
I usually either build my grammar on characters directly, such as by using productions like noun(man) --> "man"
. This way you don't have to worry about tokenizing. You can also benefit from things in the dcg/basics library.
If you insist on having a separate tokenizing step, your final call will look something like phrase(tokens(T), Input), phrase(sentences(S), T)
. The tokens//1
rule is going to look something like this:
tokens([T]) --> token(T). tokens([T|Ts]) --> token(T), whitespace, tokens(Ts).
token(T) --> tokenchars(Ch), { atom_chars(T, Ch) }.
tokenchars([C|Cs]) --> tokenchar(C), tokenchars0(Cs). tokenchars0([C|Cs]) --> tokenchar(C), tokenchars0(Cs). tokenchars0([]) --> [].
tokenchar(C) --> [C], { char_type(C, graph) }.
whitespace --> []. whitespace --> [W], { char_type(W, white) }, whitespace.
There's something annoyingly wrong with this but I'm at work and can't dig into it right now in depth. But this will break your input into tokens. You probably want to use something like read_line_to_string/2 to get the input.
A few thoughts:
If you're already able to get the largest value, then you don't need to do anything fancy. You still have the original list (it wasn't destroyed). You just need to remove the largest element from that list. The easiest way, if you're allowed to use builtins, is to use <code>selectchk/3</code> (contrast that with <code>select/3</code>, which behaves differently in the case of duplicates).
is_triangle(Sides) :- list_max(Sides, LargestSide), selectchk(LargestSide, Sides, SmallerSides), % check that the sum of SmallerSides is > LargestSide
If you can't use builtins, then you could implement that functionality yourself.
Don't forget that you have a constrained problem. Yes, you're dealing with a list of numbers, but you know that it's a list with 3 numbers (or, after you remove the largest, with 2 numbers). Pattern matching to extract the 3 (or 2) elements of the list into separate variables might be useful.
Good use of ->
. It's common to see !
used in cases like this, but I think ->
is more readable. Note that !
and ->
can both make your code non-relational, but if you're dealing with numeric expressions, then you're already in non-relational land (imagine if I called list_max([A, 2, 3], 3)
).
You don't need to quote the dot. .(a, .(b, .(c, [])))
. You can get this working if you pass --traditional
when you start SWI-Prolog:
$ swipl --traditional Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.11-6-gde6e44cd9) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- X = .(a, .(b, .(c, []))). X = [a, b, c].
But you cannot use the a.b.c.[]
notation for sure.
Either way, in this code, there is no definition for aless/1
(as called towards the bottom, aless(H.H1)
) nor is there a single use of alessx/1
(as defined close to the top, alessx([].[_|_])
). And if the dot was a normal atom, and defined as an operator, then the [].[_|_]
thingy would be a list with at least two elements, with an empty list as the first element.
But good that you took the time to provide some historical perspective to this. Reading Prolog code from textbooks is sometimes a bit like archeology.
So I still don't know for sure:
It sounds a bit funny that you are asked about the board size (a single integer?) and you then actually give this as input to your program instead of getting it as an answer of your query.
The reason why I am asking, it is great that you have written such a nice big program, but there is a lot of weird stuff going on in it. It is difficult to say what is necessary and what isn't if the problem statement is unclear.
And brute-forcing this kind of combinatorial problems is usually a starting point. The final solution usually uses constraints in some form. Again, take a careful look at the solution to N-Queens I linked:
https://github.com/SWI-Prolog/pengines/blob/master/apps/scratchpad/examples/queens.pl
and compare it to this solution of the N-Queens that uses a constraint library:
http://www.swi-prolog.org/pldoc/man?section=clpfd-n-queens
Both use constraints in some form.
It is listed under "Arithmetic Functions". At the top of that subsection, it reads:
"Arithmetic functions are terms which are evaluated by the arithmetic predicates..."
This means that you can give any of the arithmetic predicates one of the arithmetic functions and it will do the right thing. But again, those are not really functions, they are terms that are evaluated by predicates.
Here is what it means:
Unification, X is just a term:
?- X = 2 + 3. X = 2+3.
Again, unification, both X and Y are just terms:
?- X = 2 + 3, Y = X / 2. X = 2+3, Y = (2+3)/2.
Using the arithmetic predicate is/2
finally evaluates the term min(2, (2+3)/2)
and unifies the result with Z:
?- X = 2 + 3, Y = X / 2, Z is min(2, Y). X = 2+3, Y = (2+3)/2, Z = 2.
If I'm just shuffling strings around or making simple changes, I use SWI 7 string handling predicates, and I find that they provide everything needed for most simple tasks. I only use character lists and DCGs if I"m doing proper parsing. But I don't believe SWI strings are ISO complaint or portable across many different Prolog flavors.
Hello.
Your code is so clean and works (tried it in SWISH), at this stage I probably should be ashamed to even ask follow up questions. But I have to because I can't make it to work in Visual Prolog.
Specifically, VP doesn't seem to like the "==" part. And I lack the knowledge to make it work.
Could you explain what "==" does (is it just a "not identical" predicate?), how is it different from "=" so i have some keywords to search VP documentation for?
I've read http://www.swi-prolog.org/pldoc/man?section=standardorder and have been reading http://wiki.visual-prolog.com/index.php?title=Language_Reference/Built-in_entities for the last hour but to no avail.
Also I guess I should ask what does the number after predicate means (example from swi documentation "==/2". Is it the number of arguments?)
Explicit evaluation is indeed nifty. It lets Prolog have all the expressive and reflective power of Lisp's homoiconicity without having to worry about quoting and quasi-quoting. If one wants functional notation and implicit evaluation, you can just load a module (e.g., library(func)), write your own functional syntax using term_expansion, or use an implementation like Ciao that has it's own standard functional syntax.
One might reasonably suggest some Prolog implementations are "broken" for any number of reasons, but /u/codercoder's silly gripe isn't one of them.
At least in Ciao Prolog, you can use assertions to emulate "type-checking". Keep in mind that assertions or explicit calls to type-checking predicates happen at runtime so it's not proper type checking. But don't worry too much about this, because usually prolog predicates will fail if you don't use the correct types.
You should implement is_cat/1 enumerating all the clauses:
is_cat(a). is_cat(b).
This is better because modern prolog systems implement clause indexing.
Here you can find the meaning of the predicate definition symbols (+,-,?,...). I hope this helps.
I think that the second predicate is better, but you need to explain what a duplicate is in the context of your problem. For example, does the order matter?
?- version.
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.1.30)
[...]
true.
?- listing(forall). :- meta_predicate forall(0,0).
forall(A, B) :- + ( call(A), + call(B) ).
true.
;)
I can definitely see why one would prefer the latter, since it lets you keep your head in the mode of backtracking. I have learned Prolog with SWI Prolog, and have had a heavy bias towards the declarative ideal. I have thus tended towards declarative idioms whenever possible, and thus cultivated a style that relies on higher-order predicates to abstract procedural code into declarative forms. Thus, I will tend to use once/1 instead of !
, when it makes sense, I'll reach for maps and folds instead of explicit recursion, and use forall
and foreach
instead of just making explicit failure driven loops.
I should also probably note that my foundations are spotty, being self-taught and only a hobbyist. I bet that, if I had a proper eduction in logic programming, I would have made my peace with Prolog's elegant impurities some time go, and I would have made myself in proper backtracking already. Instead, I am only coming to embrace these things now :)
Which Prolog do you mainly use?
Don't know which version you are using, but SWI Prolog has findall/3 (and others might also) for this kind of thing.
In this case, you'd get something like
findall(G, gamespub(Dev, G, ^Y, ^Pub,^RS, ^NR), Games). to get a list of all games for a certain developer (assuming Dev is bound) bound to Games.
We can help more if you show us the code you're working with and give details, (like the Prolog implementation you're working with). Assuming you're using SWI-Prolog:
/u/walrusesarecool's answers tells you how to "remove" the first item of a list. Really, it's just destructuring a list into it's head and tail. This is a very basic operation, and you should learn about it in any introductory material you choose to work with. Here's one intro to lists in prolog: http://en.wikibooks.org/wiki/Prolog/Lists
Here is a predicate that will pick a random member of a list and provide a list with that element removed:
select_random(List, Element, NewList) :- random_member(Element, List), select(Element, List, NewList).
<code>random_member/2</code> is in the SWI-Prolog library(random)
, which is loaded by default.
Your expectation is reasonable: since Prolog uses closed world assumption, not finding the predicate could simply be a failure rather than an error. Your prolog implementer had decided that for debugging it is better to be an error than a silent failure. If you don't like that there is typically a metalogical predicate to look up known predicates. For SWI see this example http://www.swi-prolog.org/pldoc/man?predicate=current_predicate/2
I would also add: https://www.amazon.co.uk/Clause-Effect-Programming-Working-Programmer/dp/3540629718 very practical to get you started or https://book.simply-logical.space/about.html if you want to do AI but is less immediately practical.