« first day    last day (1670 days later) » 

2:44 AM
Am I doing it wrong? I just copied the example
 
3:10 AM
@ConorO'Brien The tutorial is for ISO Prolog and maybe SWI isn't standard-compliant?
 
3:54 AM
@ConorO'Brien I've been playing around a bit and I'm pretty sure whatever dialect The Power of Prolog uses isn't compatible with SWI.
 
yeah, I've found the same
shame, really
also you can enter definitions in swi like this:
[user].
a(X).
^D
(supposedly, I can't get ^D to work on my computer)
 
4:11 AM
I'll be completly honest, I've been doing consult('/dev/stdin').
That's great.
 
 
3 hours later…
7:29 AM
On TIO, your code into code and your query goes into the input
For whatever reason, the author of the power of prolog does not mention explicitely that you have to include the CLP(FD) library to make integer arithmetic work
@Pavel X is 2+2 is right but this is not the declarative way to do integer arithmetic in Prolog. You should include the CLP(FD) library by including :- use_module(library(clpfd)). (or by querying use_module(library(clpfd)).), and then you can use constraint arithmetic: X #= 2+2. In that case it doesn't change anything, but try X * X #= 4 and X * X is 4 to see the major difference
@Pavel If you have SWI-Prolog on your computer, you can query make. after changing your code file to update the rules base without having to reconsult.
 
 
8 hours later…
3:13 PM
@Fatalize I thought that the way is worked was very unprology, but didn't bother to search.. Why is is available by default and not #=?
 
@dzaima Because something something iso-compliance
I don't really know the reason but all I know is that it's dumb
 
@Fatalize oh okay
@Fatalize :O
 
the only benefits of is is that it's faster, but for "simple" operations this is completely negligible
and anyway Prolog isn't the language you need if speed is crucial
@dzaima In Brachylog, there is no way to do is-like computations with integers. They all use CLP(FD) (which I think is the only declarative language where this is the case)
 
@Fatalize What does CLP(FD) even mean?
 
Constraint Logic Programming (on Finite Domains)
 
3:21 PM
That's a mouthful :P
 
basically anything CLP(X) is about putting constraints on variables
and FD says that in this case it's on integers
(and finite domains of integers in particular)
For example there is also a library CLP(Q) which is for rational numbers constraint arithmetic
and CLP(B) for booleans, which is useful for things like SAT problems
 
would it be right to say that the main form of calculation in vanilla prolog is through reduction to a base case? I've worked through reversing a list in prolog and addition using peano, and it all seems to use an accumulator of some sort to keep track of state. would this be a correct observation?
 
The main form of calculation is recursivity, so in a sense yes
accumulators is a very common computation pattern in Prolog
and in general, you indeed pass the state through different predicates using arguments, instead of manipulating global variables
@ConorO'Brien A good exercise imo is to try to implement factorial (using CLP(FD) for int operations). There are two recursive ways of doing it, and one is much better than the other
 
hm, ok, I'll have to familiarize myself with CLP(FD)
 
it's pretty much the same as the "normal" int relations, except you add a hashtag in front of them (#= instead of is, #> instead of >, etc.)
I guess I can formaly write the following exercise:
 
3:38 PM
Is multiplication #*
Or just *
 
> Write a predicate `f/2` (i.e. a predicate with name `f` and 2 arguments) which states that its second argument is the factorial of its first argument.

To do integer operations, add `:- use_module(library(clpfd)).` at the beginning of your code base. Some operations you might need are (with dummy variables): `A #> B`, `A #= B * C`, `A #= B - C`.
 
Oh ty
 
@Pavel Just *. Only the actual relations (like equality, greater than, etc.) have that hashtag
 
|: :- use_module(library(clpfd)).
|: factorial(1, 1).
|: factorial(I, R):-
|:   I #> 0,
|:   I #= I0+1,
|:   factorial(I0, R0),
|:   R #= R0 * I.
It works, but returns false. for some reason?
?- factorial(3, R).
R = 6 ;
false.
 
@Pavel Try it for 1, and see what happens
 
3:41 PM
Also, I want to say that I feel incredibly smart right now.
@Fatalize Same thing (but R = 1 ;)
 
And for 0? ;)
 
Just false. Which makes sense, you can't check the factorial of 0, right?
 
Ah, well you can actually, it's just 1.
 
Oh
 
@Fatalize I've got this
 
3:43 PM
So really your code was right with what you knew. In reality your base case should be factorial(0,1)., but otherwise your solution is what I expected :)
 
factorial(1, 0). then.
Ye
 
0,1 not 1,0
 
Right
 
@dzaima See what happens when you replace 1000 by -1
 
@Fatalize about what I expected, input validation is discouraged on PPCG :P
 
3:46 PM
@Pavel It returns false because it think there might be another answer. Indeed, once it reaches the base case, it didn't check if reusing the second rule instead of the base case would yield another solution. So when you press ;, it tries it, and finds that there is in fact no other solution. So this works as expected!
@dzaima if you see it like this I guess… :p
Now, for both of you, observe this: if you move your R #= R0 * I / X #= F*X before the recursive call, then it still works as expected.
(which obviously wouldn't be the case with imperative languages)
 
@Fatalize oh now that's the beauty I expected from prolog (and didn't get with is..)
 
@dzaima You can't get it with is because it indeed expects that the value of F is known in order to computer X, which it wouldn't know before recursively calling the predicate
 
Prolog is awesome confirmed
 
with CLP(FD), it only constrains the variable called F such that Y = F*X, and will retroactively compute the value of Y once it is unambiguously possible to do so
 
?- factorial(3, 6).
true ;
false.
._.
 
3:51 PM
Second "mindfuck": instead of querying factorial(3,X)., try querying factorial(X,6).
 
@Pavel there's only one time that's correct trough the paths of execution
 
@Pavel I know it looks confusing but it's actually right, the interpreter is just telling you "I thought there might be more, but nevermind"
 
@Fatalize It found 3 then got stuck in an infinite loop
 
@Pavel What's you exact code right now?
 
|: :- use_module(library(clpfd)).
|: factorial(0, 1).
|: factorial(I, R):-
|:   I #> 0,
|:   I #= I0+1,
|:   factorial(I0, R0),
|:   R #= R0 * I.
It works if I try it again
I'm not sure why is got stuck
The prolog REPL seems a bit finicky.
 
3:54 PM
If you press ; after finding 3, it will go in an infinite loop again
 
Mm, yes it does.
How can I prevent that?
 
The reason for this, is that your recursive call is indeed before your R #= R0 * I constraint. Because of this, it means that, when R is known but I isn't (instead of the opposite as before), it will call factorial(I0,R0) without knowing anything about either I0 nor R0
Therefore, it will always find a way to satisfy the first constraints and call itself recursively infinitely
Lesson is: always apply the needed constraints before making recursive calls.
 
So if I swap the last two statments it'll work
 
Yes
The second lesson, after fixing this, is that while you only wrote a "compute the factorial" predicate, you actually end up also with a "what number has this factorial" predicate, for free!
In fact, you also end up with a factorial numbers generator:
?- factorial(X,Y).
X = 0,
Y = 1 ;
X = Y, Y = 1 ;
X = Y, Y = 2 ;
X = 3,
Y = 6 ;
X = 4,
Y = 24 ;
X = 5,
Y = 120 ;
…
All of those behaviors for the price of a few lines of codes
 
Holding down the spacebar as it does this is fun
 
@ConorO'Brien You might want to add A #> 0,
 
@ConorO'Brien This is the simple implementation that Pavel and dzaima came up with, yes
 
is there a better one?
 
As Pavel said, if you don't constrain that A is greater than 0, then it will do badly for negative numbers
The better one is the second exercise:
> Observe that factorial(40,Y). returns Y = 815915283247897734345611269596115894272000000000 immediately, while factorial(X,815915283247897734345611269596115894272000000000). returns X = 40 really slowly. (and for the factorial of 100, it's obviously way worse). Implement a new version of the factorial predicate which works quickly in both cases.
Hint: accumulators are useful
(have to go, good luck :p)
 
o/
hmm
 
4:27 PM
@Fatalize I don't know why, but this works ¯\_(ツ)_/¯
 

« first day    last day (1670 days later) »