SWI-Prolog is still one of the best implementations, and its maintainer is still active. The quality and performance has always been high.
So, I don't think its fair to say that Prolog has been killed. :)
For general purpose:
Python is beginner friendly
C is harder but let you understand really how it works
Java is ok, i do not like it very much but it's good when you start too
Haskell is great for people liking math as it is functionnal but is quite different from the other 3.
OCaml is in the same way as Haskell
And less general purpose (i list those i like):
First off, I should tell you I'm pretty green when it comes to Haskell and I'm embarrassingly ignorant when it comes to pretty much all techniques in applied math. That being said, you can get a super simple constraint solver just using list comprehensions:
solve_ex1 = head [x | x <- [1..], [1, 2, 3] == [1, x * 2, 3]] => 1
solve_ex2 = head [x | x <- [1..], x * 2 == 6] => 3
This describes all the values of x where x is a positive integer and the guard is satisfied.
In general, what you are describing is the forte of logic programming. In particular, you may want to look at constraint logic programing. The docs on this Prolog library give a good sense for what it's capable of: http://www.swi-prolog.org/pldoc/man?section=clpfd
So, I think /u/davorlju's suggestion of miniKanren is right on the money. There are also other logic programming libraries for Haskell I've found via googling those terms.
Why logic programming in particular? Languages like Prolog strike me as really interesting and useful for certain classes of problem, but probably too weird for general use. I mean, it's great when you're doing pure deduction, but things get a little weird when you start using "one-way" predicates like is
.
I see the parameter annotations that SWI-Prolog defines as evidence that logic programming semantics aren't a great fit for things like IO and GUIs.
It's very strange and disappointing that Douglas Hofstadter would say things that are so wrong. Perhaps he was oversimplifying?
Prolog is a programming language well suited to building automated reasoning systems. It's basic deduction mechanism can be extended to implement others, not necessarily "based on very rigid, deductive logic". The Fifth Generation Computer Systems project was a Japanese project. It's goal was to build a supercomputer that would be the platform for future advances in artificial intelligence not that "all of human knowledge was going to be encoded in databases with Prolog". It's failure was not the cause of the AI Winter in the US (obviously not, because the Americans were using Lisp, not Prolog), although it failed for similar reasons.
"Prolog was one of the silliest approaches I've ever heard of, and it fell to the ground in shambles." Clearly not. Many of us are still using it! :-)
If Hofstadter wanted to attack AI programming languages, he might as well have criticised McCarthy for wanting to build AI systems in Lisp, which would have been an equally ridiculous criticism. A more valid target here would have been Doug Lenat's Cyc, which, unlike Prolog, was - and to a lesser extent still is - an attempt to encode "all of human knowledge".
> 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).
Many prolog systems have real constraint solver build in to them as well, in addition to the core back tracking abilities. See for instance swi-prolog's documentation on the subject
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.
Nice post! I guess you used SWI-Prolog ? It is probably better to use +/1 rather than not/1(e.g., SICStus Prolog does not have not/1; see also http://www.swi-prolog.org/pldoc/man?predicate=not/1). We also produced a logic encoding of the puzzle, but using the predicate logic + arithmetic + set theory (aka the B method) and solved using a tool written in Prolog. The solution can be found here: http://stups.hhu.de/ProB/w/Cheryl%27s_Birthday. You can also try out the solution online.
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.
$ prolog Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.6.4) Copyright (c) 1990-2013 University of Amsterdam, VU Amsterdam SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- a = b. false. ?- a=a. true.
Sigh.
I am uncomfortable with articles that use language like "everyone agrees" without any citations to back the claim. Further, the article disparages Prolog and AFAICT the author does not understand Prolog well, or that a modern implementation of Prolog can be quite fast and flexible, supporting multiple programming paradigms.
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.
Googling terms in Makefile.am, I find this. Don't know much about Prolog, so maybe there are a multitude of compiler/intepreters called plc
Edit: ah nope, it's SWI Prolog, taken from configure.in at the top level
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.
Reformatted for anybody who comes along after:
subset(_,[]).
subset([H|T],[H|T2]):- subset(T,T2).
subset([_|T],T2):- subset(T,T2).
subset2(S,S2):- findall(X, subset(S,X), L), member(S2, L).
member(H,[H|_]).
member(X,[_|T]):- member(X,T).
So member
here is a re-implementation of the built-in <code>member/2</code> predicate. Among other uses, it lets you test to see whether an item is a member of a list and, alternatively, it lets you enumerate the members of a list.
findall
is used to collect all the solutions to a query into a single list. Prolog typically produces a single sequence of solutions to the top-level query. That's fine, but you sometimes need to see all the solutions at once. findall
can do that for you. Learn Prolog Now! has a section covering it.
I'm not at all clear on why subset2/2
even exists. It uses findall
to collect the solutions, but then uses member
to turn them back into distinct solutions. That seems pointless.
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).
That's just append: http://www.swi-prolog.org/pldoc/man?predicate=append/3
Think about what it means if the list is a palindrome, and if that doesn't make it obvious enough, write those examples out with a palindrome in each possible location/list.
Theoretically, yes. Practically, no. There's no real general solution to every program for this ... this would really amount to what you really need done.
One semi-practical way would be to load up a VM, start the program, and make a save-state at your chosen moment. You could then load up a new VM instance at that state at any time.
If it's for your own program, there are ways to do work incrementally, save the current progress to disk, and then continue working when it is reopened.
If, by chance, you're working in prolog (i'm going to assume not) you can do just that http://www.swi-prolog.org/pldoc/doc/swi/library/qsave.pl but prolog is much different than normal programs.
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?
More CHR in SWI-Prolog (and, as usual, I'm late to the party). It's packaged as a PrologScript.
#!/usr/bin/env swipl
:- use_module(library(chr)).
:- initialization main.
main :- prompt(_, ''), read_line_to_term(NumLines), read_n_lines_to_terms(NumLines, Positions), maplist(position, Positions), closest_positions(Pair), format('(~w) (~w)~n', Pair), halt.
%% LOGIC
points_distance((X1,Y1), (X2,Y2), D) :- D is sqrt((X2 - X1)^2 + (Y2 - Y1)^2).
%% CONSTRAINTS
:- chr_constraint position/1, distance/2, closest_positions/1.
distance @ position(P1), position(P2) ==> P1 @< P2 | points_distance(P1, P2, D), distance([P1,P2], D).
minimum_distance @ distance(,A) \ distance(,B) <=> A < B | true.
clean_up_positions @ closest_positions() \ position() <=> true.
return @ closest_positions(C), distance(P,_) <=> C = P.
%% IO
read_line_to_term(T) :- read_line_to_codes(current_input, Cs), read_term_from_atom(Cs, T, []).
read_n_lines_to_terms(N, Points) :- length(Points, N), maplist(read_line_to_term, Points).
Usage
$ cat 232_input1.txt | ./232.pl (5.305665745194435,5.6162850431000875) (5.333978668303457,5.698128530439982)
clpfd is an acronym for Constraint Logic Programming over Finite Domains, which is a special case of constraint logic programming.
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
>I agree
Then you understand why your measure of a "good conclusion" is fundamentally flawed.
>What makes you think that I haven't?
You asked me about algorithms for correct logical deduction. It might be worthwhile to revisit those topics.
>No one uses it in debates. No one.
This is not correct. I've seen formal proofs used in debates very effectively. Formal logic may not be used in political debates, but they are used. Regardless, this has zero bearing one what future AIs will find convincing.
>Are you implying that someone built a better tool using propositional logic, and so I am wasting my time?
No, I'm saying that future AIs may not accept logically sound arguments, much less merely persuasive arguments.
>You are saying my tool has no hope of ever helping people use logic better?
I'm saying that it does not use logic to begin with, and may also suffer from subjectivity.
>Can you send me a free copy of the tool that uses propositional logic that is better than my Microsoft Access Database?
Here is a website where you can download Prolog, an extremely powerful declarative programming language: http://www.swi-prolog.org/
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 :)
Not sure where they're getting the dissm
variable from, but the language is prolog
.
atan() (arctan) is the mathematical inverse of tan(). In prolog it can take two arguments, being the Y and X values. According to this it is used to convert between rectangular and polar co-ordinate systems.
That's about as much as I can help with this one sorry.
It would not make much sense to call single Prolog "functions" (actually predicates) in your imperative programming language, but there are interfaces that allow you to write and query Prolog programs from within other languages. For Java you could use JPL. Such interfaces exist for many other languages, since (SWI-) Prolog provides a Foreign Language Interface.
So, you're thinking whether it's worth to learn Prolog to help you in your future jobs? :P If you do so, consider this Essay from Paul Graham.
But I can't really tell you whether the industry uses it that much or not, but I know that a friend of mine used it in a project for a hospital, which should help finding the right volunteer at the right time (so Prolog for decision-making). I happen to know that Firewall Builder uses Prolog too.
Also Prolog is used in fields like AI and computational linguistics (I haven't mentioned that yet, but Prolog was actually intended to be used by computinal linguists for natural language processing). As far as I know, Prolog is basically THE language for computational linguists. So it's used quite frequently. See e.g. Wikipedia for more.
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)
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|...].
> Not sure what to do.
More clauses with more patterns / more predicates!
As your recursive eo
predicate walks the list, you'll need to detect whether the "surviving" element is a list or an atom. Testing for a list is easy; you've already demonstrated how to test for the empty list ([]
) and nonempty list ([_|_]
). The other thing you need is to test for the case that it's not a list. You can use the Prolog type-test predicates. You could test using number/1
specifically, or alternatively atom/1
or atomic/1
(which I think will both work for your usecase).
If you detect a list, recurse!
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.
Sudoku is an excellent exercise to solve using a completely different approach, if you are learning or want to try something "unusual": Logic programming (using the Prolog programming language, for example, using SWI-Prolog).
In logic programming, you "teach" the computer the problem's rules and constraints, instead of implementing how to solve it. After trying it, you could feel Python is no longer the best tool for this particular problem (and that's OK!).
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...
Yes, after both of those sub-clauses have evaluated, then A
will be ground.
It's not ground just that B
has a value, though. It's ground because B
also has a ground value. This query would fail:
?- A = 2 + B, B = X + Y, ground(A)
B
is bound, but it's not bound to a ground value, so A
is also not ground.
As an aside, I should point out that A = 2 + B
might not do what you think. Consider this query:
?- B = 3, A = 2 + B, writeln(A).
What would you expect it to print? If you run it, what does it actually print?
In Prolog, +
doesn't perform arithmetic. +
is instead an inline operator that constructs a compound term. A + B
is equivalent to +(A, B)
, and both represent a data structure whose name is +
and whose args are A
and B
. If you want to actually perform arithmetic, you can use the <code>is/2</code> predicate.
So getting back to your example, if you do:
?- A = 2 + B, B = 4
... then A
will be bound to the compound term +(2, 4)
(which we typically write as 2 + 4
). This is a compound term without any unbound variables, so it's ground.
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.
Swi-Prolog is a version of prolog that is free and open source. If you have not programmed in Prolog before it is a bit of mind bender. But it is very powerful and very good for the semantic web. Swi-prolog includes a number of ways to reason with RDF data.
You don't need to model problems like these with constraint logic programming. They can be modelled just as nicely with pure prolog. However in many cases indeed .... libraries liked clpfd or clpb can make problems much more tractable. No, you don't need to know the hard implementation details to use libraries/frameworks like these.
Here are some links I recommend:
http://www.pathwayslms.com/swipltuts/clpfd/clpfd.html
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.
Using CHR in Prolog (with SWI-Prolog's library(chr)). I'm just starting to learn CHR. It's quite fun and seems well suited for this kind of problem. As always: suggestions and questions welcome.
:- use_module(library(chr)).
:- chr_constraint card/1, set/1.
match(A, B, C) :- A = B, B = C, A = C ; A = B, B = C.
%% Given three cards ==> if their respective elements match | then form a set. card(A), card(B), card(C) ==> maplist(match, A, B, C) | set([A, B, C]).
%% Keep S1 \ discard S2 <=> if S1 and S2 are the same set S | true. set(S1) \ set(S2) <=> sort(S1, S), sort(S2, S) | true.
%% Output the sets in the desired form. set(S) ==> format('~s ~s ~s~N', S).
Challenge:
?- maplist(card, [DP2H
, DP1F
, SR2F
, SP1O
, OG3F
, SP3H
, OR2O
, SG3O
, DG2H
, DR2H
, DR1O
, DR3O
]).
OG3F SR2F DP1F
DR2H DG2H DP2H
DR2H OR2O SR2F
DR2H OG3F SP1O
DR3O DG2H DP1F
DR3O SP3H OG3F
...
Edited: added explanatory paraphrases above the CHR rules and rendered the code more elegant.
Prolog:
#!/usr/bin/env swipl
:- initialization main.
main :- prompt(_,''), ( at_end_of_stream -> halt ; read_line_to_codes(current_input, Word), word_status(Word, Status), format('~s ~s~n', [Word, Status]), main ).
word_status(Codes, Status) :- msort(Codes, Sorted), ( Codes == Sorted -> Status = 'IN ORDER' ; reverse(Sorted, Codes) -> Status = 'REVERSE ORDER' ; Status = 'NOT IN ORDER' ).
Edit: I didn't see there were other Prolog answers before submitting mine! I suppose it's okay, since each is a somewhat different approach :)
Edit: I realized I misunderstood the challenge. :( It has now been fixed. I followed /u/dict in making this a PrologScript so the input can be piped in. E.g.,
$ echo "billowy biopsy chinos defaced chintz sponged bijoux abhors fiddle begins chimps wronged" | ./scratch.pl billowy IN ORDER biopsy IN ORDER chinos IN ORDER defaced NOT IN ORDER chintz IN ORDER sponged REVERSE ORDER bijoux IN ORDER abhors IN ORDER fiddle NOT IN ORDER begins IN ORDER chimps IN ORDER wronged REVERSE ORDER
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?
Indeed, you don't have column names, because you don't have columns. You don't have tables, either. Prolog is not a relational database, really. It is a general purpose programming language. Its execution model is based on finding proofs. In Prolog, the position of the argument is what is relevant, not its name. This is not for density purposes, but for efficiency purposes. There are several ways you can make Prolog understand named arguments, depending on the trade offs you are willing to make and on the use case. In the most trivial example, you can have a predicate that maps the named argument from a compound term:
arg_foo(a, foo(A, , _), A). arg_foo(b, foo(, B, ), B). arg_foo(c, foo(, _, C), C).
A similar approach that does not sacrifice efficiency is implemented by <code>library(record)</code>.
Or if you need a more generic data structure with named arguments, you can use SWI-Prolog's dicts.
?- 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
What's the computational complexity of even a static graph in prolog? What about one that needs to dynamically change (nodes and edges)?
I have a little feeling that it will not blow my mind, but you can try.
Additionally, while it might very well be possible to build a good graph library in Prolog, it will never ever match C++ levels of performance and there we have hit the real problem; for real systems Prolog is just too slow.
http://www.swi-prolog.org/pldoc/doc/swi/library/ugraphs.pl seems to be the state-of-the-art in Prolog land when it comes to graphs. So, not only are Prolog experts not able to build something useful, you are expecting some random n00b to be able to do that much better.
So, I hereby conclude my proof that Prolog in its current state is not going to blow anyone's mind and I also conclude that you probably never ever used Prolog for anything of significance.