Related
After doing some Prolog in uni and doing some exercises I decided to go along somewhat further although I got to admit I don't understand recursion that well, I get the concept and idea but how to code it, is still a question for me. So that's why I was curious if anyone knows how to help tackle this problem.
The idea is given a number e.g. 45, check whether it is possible to make a list starting with 1 going n+1 into the list and if the sum of the list is the same as the given number.
So for 45, [1,2,3,4,5,6,7,8,9] would be correct.
So far I tried looking at the [sum_list/2][1] implemented in Prolog itself but that only checks whether a list is the same as the number it follows.
So given a predicate lijstSom(L,S) (dutch for listSum), given
?- lijstSom(L, 45)
L = [1,2,3,4,5,6,7,8,9];
False
My Idea was something along the line of for example if S = 45, doing steps of the numbers (increasing by 1) and subtracting it of S, if 0 is the remainder, return the list, else return false.
But for that you need counters and I find it rather hard to grasp that in recursion.
EDIT:
Steps in recursion.
Base case empty list, 0 (counter nr, that is minus S), 45 (S, the remainder)
[1], 1, 44
[1,2], 2, 42
[1,2,3], 3, 39
I'm not sure how to read the example
?- lijstSom(L, 45)
L = [1,2,3,4,5,6,7,8,9],
False
...but think of the predicate lijstSom(List, Sum) as relating certain lists of integers to their sum, as opposed to computing the sum of lists of integers. Why "certain lists"? Because we have the constraint that the integers in the list of integers must be monotonically increasing in increments of 1, starting from 1.
You can thus ask the Prolog Processor the following:
"Say something about the relationship between the first argument of lijstSom/2 and the second argument lijstSom/2 (assuming the first is a list of monotonically increasing integers, and the second an integer):
lijstSom([1,2,3], Sum)
... should return true (because yes, there is at least one solution) and give Sum = 6 (because it constructs the solution, too ... we are some corner of Construtivism here.
lijstSom(L, 6)
... should return true (because yes, there is at least one solution) and give the solution [1,2,3].
lijstSom([1,2,3], 6)
... should return true (because yes, [1,2,3] has a sum 6); no further information is needed.
lijstSom(L, S)
... should an infinite series of true and pairs of solution ("generate the solutions").
L = [1], S = 1;
L = [1,2], S = 3;
L = [1,2,3], S = 6;
...
lijstSom([1,2,3], 7)
...should return false ("fail") because 7 is not in a relation lijstSom with [1,2,3] as 7 =/= 1+2+3.
One might even want things to have Prolog Processor say something interesting about:
lijstSom([1,2,X], 6)
X = 3
or even
lijstSom([1,2,X], S)
X = 3
S = 6
In fact, lijstSom/2 as near to mathematically magical as physically possible, which is to say:
Have unrestricted access to the full table of list<->sum relationships floating somewhere in Platonic Math Space.
Be able to find the correct entry in seriously less than infinite number of steps.
And output it.
Of course we are restricted to polynomial algorithms of low exponent and finite number of dstinguishable symbols for eminently practical reasons. Sucks!
So, first define lijstSom(L,S) using an inductive definition:
lijstSom([a list with final value N],S) ... is true if ... lijstSom([a list],S-N and
lijstSom([],0) because the empty list has sum 0.
This is nice because it gives the recipe to reduce a list of arbitrary length down to a list of size 0 eventually while keeping full knowledge its sum!
Prolog is not good at working with the tail of lists, but good with working with the head, so we cheat & change our definition of lijstSom/2 to state that the list is given in reverse order:
lijstSom([3,2,1], 6)
Now some code.
#= is the "constain to be equal" operator from library(clpfd). To employ it, we need to issue use_module(library(clpfd)). command first.
lijstSom([],0).
lijstSom([K|Rest],N) :- lijstSom([Rest],T), T+K #= N.
The above follows the mathematical desiderate of lijstSom and allows the Prolog Processor to perform its computation: in the second clause, it can compute the values for a list of size A from the values of a list of size A-1, "falling down" the staircase of always decreasing list length until it reaches the terminating case of lijstSom([],0)..
But we haven't said anything about the monotonically decreasing-by-1 list.
Let's be more precise:
lijstSom([],0) :- !.
lijstSom([1],1) :- ! .
lijstSom([K,V|Rest],N) :- K #= V+1, T+K #= N, lijstSom([V|Rest],T).
Better!
(We have also added '!' to tell the Prolog Processor to not look for alternate solutions past this point, because we know more about the algorithm than it will ever do. Additionally, the 3rd line works, but only because I got it right after running the tests below and having them pass.)
If the checks fail, the Prolog Processor will says "false" - no solution for your input. This is exactly what we want.
But does it work? How far can we go in the "mathematic-ness" of this eminently physical machine?
Load library(clpfd) for constraints and use library(plunit) for unit tests:
Put this into a file x.pl that you can load with [x] alias consult('x') or reload with make on the Prolog REPL:
:- use_module(library(clpfd)).
lijstSom([],0) :-
format("Hit case ([],0)\n"),!.
lijstSom([1],1) :-
format("Hit case ([1],1)\n"),!.
lijstSom([K,V|Rest],N) :-
format("Called with K=~w, V=~w, Rest=~w, N=~w\n", [K,V,Rest,N]),
K #= V+1,
T+K #= N,
T #> 0, V #> 0, % needed to avoid infinite descent
lijstSom([V|Rest],T).
:- begin_tests(listsom).
test("0 verify") :- lijstSom([],0).
test("1 verify") :- lijstSom([1],1).
test("3 verify") :- lijstSom([2,1],3).
test("6 verify") :- lijstSom([3,2,1],6).
test("0 construct") :- lijstSom(L,0) , L = [].
test("1 construct") :- lijstSom(L,1) , L = [1].
test("3 construct") :- lijstSom(L,3) , L = [2,1].
test("6 construct") :- lijstSom(L,6) , L = [3,2,1].
test("0 sum") :- lijstSom([],S) , S = 0.
test("1 sum") :- lijstSom([1],S) , S = 1.
test("3 sum") :- lijstSom([2,1],S) , S = 3.
test("6 sum") :- lijstSom([3,2,1],S) , S = 6.
test("1 partial") :- lijstSom([X],1) , X = 1.
test("3 partial") :- lijstSom([X,1],3) , X = 2.
test("6 partial") :- lijstSom([X,2,1],6) , X = 3.
test("1 extreme partial") :- lijstSom([X],S) , X = 1, S = 1.
test("3 extreme partial") :- lijstSom([X,1],S) , X = 2, S = 3.
test("6 extreme partial") :- lijstSom([X,2,1],S) , X = 3, S = 6.
test("6 partial list") :- lijstSom([X|L],6) , X = 3, L = [2,1].
% Important to test the NOPES
test("bad list", fail) :- lijstSom([3,1],_).
test("bad sum", fail) :- lijstSom([3,2,1],5).
test("reversed list", fail) :- lijstSom([1,2,3],6).
test("infinite descent from 2", fail) :- lijstSom(_,2).
test("infinite descent from 9", fail) :- lijstSom(_,9).
:- end_tests(listsom).
Then
?- run_tests(listsom).
% PL-Unit: listsom ...................... done
% All 22 tests passed
What would Dijkstra say? Yeah, he would probably bitch about something.
I am fairly new to functional programming and I do not understand my error here. I am trying to make a function that takes an integer list and returns both the sum of the even elements and the sum of the odd elements. The error I am getting is in line 1, and it states: "Error: right-hand-side of clause doesn't agree with function result type [overload conflict] ...". I don't understand the error, and I would appreciate any help in understanding my error.
fun add(nil) = 0
| add([x]) = x
| add(x :: xs) =
let
val evenList = xs;
val oddList = x :: xs
in
(hd evenList + add(tl(tl(evenList))), hd oddList + add(tl(tl(oddList))))
end;
The reason for the type error is that the function should return a pair, but your base cases don't.
I suspect you got to that code by thinking about skipping every other element, dividing the list by skipping.
There's a different way to approach this.
Consider the list [a,b,c,d].
Counting from 1, the elements are numbered
1 2 3 4
a b c d
Now consider the positions in the tail of the list.
They are
1 2 3
b c d
That is, odd positions in the tail are even positions in the entire list, and even positions in the tail are odd in the entire list.
This means that if we recursively compute "odds and evens" in the tail, we will get the sums from the tail, where its "odds" is our "evens", and if we add our head to the tail's "evens", we will get the "odds" we want.
All we need now is a good base case – and the sums of an empty list must be (0, 0).
Something like this:
fun add [] = (0,0)
| add (x::xs) = case add xs of
(odds, evens) => (x + evens, odds)
or, you can deconstruct the recursive result with a let-binding instead of case:
fun add [] = (0,0)
| add (x::xs) = let val (odds, evens) = add xs
in
(x + evens, odds)
end
I've been implementing higher order functions recursively with .foldRight() like any, all, and takeWhile as practice, but dropWhile has been elusive. _Collections.kt has the imperative way but I couldn't convert it to a recursive structure.
For reference, this is takeWhile
fun takeWhile(list:List<Int>, func:(Int) -> Boolean):List<Int> = list.foldRight(emptyList(),
{ next:Int, acc:List<Int> -> if (func(next)) acc.plus(next) else emptyList() })
First, let's outline the idea of the solution.
With foldRight, you can only process the items one by one from right to left, maintaining an accumulator.
The problem is, for an item at position i, the dropWhile logic makes a decision whether to include the item into the result or not based on whether there is an item at position j <= i that does not satisfy the predicate (include if yes). This means you cannot simply maintain the result items: for some items you already processed, you don't know if they should actually be included.
Example:
(we're processing the items right-to-left, so the prefix is unknown to us)
... (some unknown items) ... ... ... ... a b c d <--- (right-to-left)
predicate satisfied: T T F T
As we discover more items on the left, there are two possibilities:
We found the beginning of the sequence, and there were no items that gave F on the predicate:
(the sequence start) y z a b c d <--- (right-to-left)
predicate satisfied: T T T T F T
-------
drop
In this case, the prefix y z a b should be dropped.
We found an item that does not satisfy the predicate:
... (some unknown items) ... w z a b c d <--- (right-to-left)
predicate satisfied: F T T T F T
-------
include
Only at this point we know for sure that we need to include the items w z a b, we could not do that earlier because there could be the beginning of the sequence instead of item w, and then we should have dropped z a b.
But note that in both cases we are certain that the items c d are to be included into the result: that's because they have c with F predicate in front of them.
Given this, it becomes clear that, when processing the items right-to-left, you can maintain a separate list of items that are not certain to be included into the result and are either to be dropped or to be included when a false predicate result is encountered, together with the item that gave such false result.
My implementation:
I used a pair of two lists for the accumulator, where the first list is for the items that are certain to be included, and the second one for those which are not.
fun <T> List<T>.myDropWhile(predicate: (T) -> Boolean) =
foldRight(Pair(emptyList<T>(), emptyList<T>())) { item, (certain, uncertain) ->
if (predicate(item))
Pair(certain, uncertain + item) else
Pair(certain + uncertain + item, emptyList())
}.first.reversed()
Example:
val ints = listOf(0, 0, 0, 1, 0, 2, 3, 0, 0, 4)
println(ints.myDropWhile { it == 0 }) // [1, 0, 2, 3, 0, 0, 4]
See: runnable demo of this code with more tests.
Note: copying a read-only list by doing uncertain + item or certain + uncertain + item in each iteration gives O(n^2) worst-case time complexity, which is impractical. Using mutable data structures gives O(n) time.
I have just started to learn erlang(and functional programming) and I am stuck on a simple program. The object of the program is to find the largest prime factor of a number. This is my program:
lprime(N, L, D) when D == N->
if N rem D == 0 -> D;
true-> L
end;
lprime(N,L,D) ->
if N rem D == 0 ->
lprime(N/D, D, D);
true -> lprime(N, L, D+1)
end.
lprime(N)->
lprime(N,1,2).
Here's how it should run for some inputs:
lprime(3)->lprime(3,1,2)->lprime(3,1,3)->3
lprime(36)->lprime(36,1,2)->lprime(18,2,2)->lprime(9,2,2)->lprime(9,2,3)->lprime(3,3,3)->3
lprime(14)->lprime(14,1,2)->lprime(7,2,2)->lprime(7,2,3)->lprime(7,2,4)->lprime(7,2,5)->lprime(7,2,6)->lprime(7,1,7)->7
But the program always returns the first prime divisor instead. lprime(24)->2, lprime(9)->3
I wrote an equivalent(in my opinion) program in Python which I am more familiar with that performs exactly as expected:
def lprime(N, L=1, D=2):
if D==N:
if N%D == 0: return D
return L
if N%D == 0:
return lprime(N/D, D, D)
return lprime(N, L, D+1)
I also tried another version without a guard(it looks cleaner too) but this one seems to go into an infinite recursion, again the python equivalent(IMO) works as expected:
lprime2(1, L, D) ->
L;
lprime2(N,L,D) ->
if N rem D == 0 ->
lprime2(N/D, D, D);
true -> lprime2(N, L, D+1)
end.
lprime2(N)->
lprime2(N,1,2).
I was trying to debug the program using dbg, the documentation of which is very sparse and I don't understand the steps very well. The steps I used were:
1> dbg:start().
{ok,<0.35.0>}
2> dbg:tracer().
{ok,<0.35.0>}
3> dbg:tp(first,lprime, 1, []).
{ok,[{matched,nonode#nohost,1}]}
4> dbg:tp(first,lprime,3,[]).
{ok,[{matched,nonode#nohost,1}]}
5> dbg:p(all,c).
{ok,[{matched,nonode#nohost,26}]}
6> first:lprime(10).
(<0.33.0>) call first:lprime(10)
2
7> first:lprime(10,1,2).
(<0.33.0>) call first:lprime(10,1,2)
Edit: Emphasis added
I didn't find any useful information from this and I'd appreciate any pointers on how to debug effectively too but mainly I'd like to know what causes the program to fail.
You're using floating-point division instead of integer division, and that's causing exceptions in rem. But you're not seeing these exceptions because you're calling rem in a guard. You can see this by using case rather than if:
lprime2(1, L, D) ->
L;
lprime2(N,L,D) ->
case N rem D of
0 -> lprime2(N/D, D, D);
_ -> lprime2(N, L, D+1)
end.
lprime2(N)->
lprime2(N,1,2).
This will let you see the exceptions:
1> c(lp).
lp.erl:4: Warning: variable 'D' is unused
{ok,lp}
2> lp:lprime2(14).
** exception error: an error occurred when evaluating an arithmetic expression
in function lp:lprime2/3 (/tmp/lp.erl, line 7)
To fix it, use div rather than / in your second clause of lprime/3:
lprime2(N,L,D) ->
case N rem D of
0 -> lprime2(N div D, D, D);
_ -> lprime2(N, L, D+1)
end.
In general, idiomatic Erlang code uses case more than if because the latter allows only guards in its clauses.
One other thing to note is that in your code with the guards on the function clauses (as well as in your Python code), when N == D, then N rem D will always be true, so you can simplify the code:
lprime(N,_,N) ->
N;
lprime(N,_,D) when N rem D == 0 ->
lprime(N div D, D, D);
lprime(N,L,D) ->
lprime(N, L, D+1).
In the first clause, we use the same variable N for both the N and D arguments. This clause runs only when N and D are equal. There's no need for the rem test in this case.
The mistake in porting the code is that in Python, 5 / 2 == 2 while in Erlang, 5 / 2 == 2.5. You need to use the div operator: 5 div 2 == 2
1> 5 / 2.
2.5
2> 5 div 2.
2
So, in your code, replace:
lprime(N/D, D, D);
with:
lprime(N div D, D, D);
With this change, I get the expected outputs:
2> a:lprime(3).
3
3> a:lprime(36).
3
4> a:lprime(14).
7
On a side note about your logic, I'm pretty sure if N == D, N rem D will always equal 0, so you might want to simplify the code there.
I am new to Prolog and am having some difficulty fixing the errors of my first program.
The program requirement is that it divides the 2 inputs using recursion, returning 0 if the dividend is larger than the divisor, and ignores remainders.
%Author: Justin Taylor
testquotient :-
repeat,
var(Divident), var(Divisor), var(Answer), var(End),
write('Enter Divident: '),
read(Divident),
write('Enter Divisor: '),
read(Divisor),
quotient(Divident, Divisor, Answer),
nl,
write('Quotient is = '),
write(Answer),
nl,
write('Enter 0 to quit, 1 to continue: '),
read(End),
(End =:= 0),!.
quotient(_, 0, 'Undefined').
quotient(0, _, 0).
quotient(Divisor == Divident -> Answer = 1).
quotient(Divisor < Divident -> Answer = 0).
quotient(Divident, Divisor, Answer) :-
(Divisor > Divident -> Divisor = Divisor - Divident,
quotient(Divident, Divisor, Answer + 1);
Answer = Answer).
First, read up on is. Type help(is). at the SWI-Prolog's prompt. Read the whole section about "Arithmetic" carefully. Second, your first few clauses for quotient are completely off-base, invalid syntax. I'll show you how to rewrite one of them, you'll have to do the other yourself:
%% WRONG: quotient(Divisor == Divident -> Answer = 1).
quotient(Divisor, Divident, Answer) :-
Divisor =:= Divident -> Answer = 1.
%% WRONG: quotient(Divisor < Divident -> Answer = 0).
....
Note the use of =:= instead of ==.
Your last clause for quotient looks almost right at the first glance, save for the major faux pas: prolog's unification, =, is not, repeat not, an assignment operator! We don't change values assigned to logical variables (if X is 5, what's there to change about it? It is what it is). No, instead we define new logical variable, like this
( Divisor > Divident -> NewDivisor = Divisor - Divident,
and we use it in the recursive call,
%% WRONG: quotient(Divident, NewDivisor, Answer + 1) ;
but this is wrong too, w.r.t. the new Answer. If you add 1 on your way down (as you subtract Divident from your Divisor - btw shouldn't it be the other way around?? check your logic or at least swap your names, "divisor" is what you divide by ) that means you should've supplied the initial value. But you seem to supply the terminal value as 0, and that means that you should build your result on your way back up from the depths of recursion:
%%not quite right yet
quotient(Divident, NewDivisor, NewAnswer), Answer = NewAnswer + 1 ;
Next, Answer = Answer succeeds always. We just write true in such cases.
Lastly, you really supposed to use is on each recursion step, and not just in the very end:
( Divisor > Divident -> NewDivisor is Divisor - Divident, %% use "is"
quotient(Divident, NewDivisor, NewAnswer), Answer is NewAnswer+1 %% use "is"
; true ). %% is this really necessary?
Your 'Undefined' will cause an error on 0, but leave it at that, for now. Also, you don't need to "declare" your vars in Prolog. The line var(Divident), ..., var(End), serves no purpose.