I am trying to learn prolog and have come across a problem that I can't figure out. The problem is to write a prolog predicate that takes all the numbers of a list that are less than a given number and put them into a list that will be returned. For example:
input:
findNum(5, [5, 3, 5, 6, 4, 5], Y)
output:
Y = [3, 4]
Everything I've tried seems to fail. So any help would be much appreciated. Thanks.
To solve this, you will use a typical Prolog pattern of examining the elements from your input list one-at-a-time. Prolog includes a syntax for selecting the head element from a list, by unifying the list with [A | B] , the first element of the list is unified with A and the remainder of the list (or emptiness if no elements remain) is unified with B.
You should consider first how many clauses you will need. You will need one clause to handle the case of an empty list, which is also the termination condition for your recursion. Each time you examine one item of the list, you recursively examine the remainder of the list. On the final examination, the 'remainder of the list' is empty.
For the clauses which examine the head element of the list, you have two possible conditions: the element satisfies your search criterion (less than 'num'), or it does not. To represent this, implement two clauses, both of which iterate over the list, but only the first of which matches your search criteria. The clause which detects "matching" elements must be written first in your Prolog file so that it will be considered first.
% This clause is for the "empty input" case which is also used to
% discontinue the recursion when finished.
findNum( _, [], []).
% This clause completes only if the first input element is less than
% 'M'. If the clause completes, the first input element ('X') is unified
% with the output list ([X | Y]).
findNum( M, [X | L], [X | Y]) :-
X < M,
findNum(M, L, Y).
% This clause completes if the above clauses do not. Much like an "else"
% case, this clause simply removes the first input element from the list,
% the element must not match in the search clause above and so we will now
% discard it. Thus, it is unified with the "throw away" variable named "_"
findNum( M, [_ | L], Y) :-
findNum(M, L, Y).
Related
I was wondering what would be a good strategy to understand if pattern-matching in SML will proceed the Match warning.
Consider the following function:
fun f 7 (x,y) = x * 5.1 | f x (y,#"a") = y;
From first glance, it looks like it does not provide the Match warning. But if I'll run it, it will.
From my point of view, we handle all of the cases. which case we don't handle? even if f 7 (x,#"a") we know which case should be (first one).
My question is, how to decide that the function will output that waning.
Also, I would be glad for an answer why the following function is invalid:
fun f (x::xs) (y::ys) (z::zs) = y::xs::ys::zs;
without zs its valid. how does zs change it?
My question is, how to decide that the function will output that waning.
The compiler has an algorithm that decides this.
Either use the compiler and have it warn you, or use a similar heuristic in your head.
See Warnings for pattern matching by Luc Maranget (2007).
It covers the problem, algorithm and implementation of finding missing and duplicate patterns.
A useful heuristic: Line patterns up, e.g. like:
fun fact 0 = 1
| fact n = n * fact (n - 1)
and ask yourself: Is there any combination of values that is not addressed by exactly one case of the function? Each function case should address some specific, logical category of the input. Since your example isn't a practical example, this approach cannot be used, since there are no logical categories over the input.
And fact is a bit simple, since it's very easy to decide if it belongs to the categories 0 or n.
And yet, is the value ~1 correctly placed in one of these categories?
Here is a practical example of a function with problematic patterns:
fun hammingDistance [] [] = SOME 0
| hammingDistance (x::xs) (y::ys) =
if length xs <> length ys then NONE else
if x = y
then hammingDistance xs ys
else Option.map (fn d => d + 1) (hammingDistance xs ys)
It may seem that there are two logical cases: Either the lists are empty, or they're not:
The input lists are empty, in which case the first body is activated.
The input lists are not empty, in which case they have different or equal length.
If they have different lengths, NONE.
If they have equal lengths, compute the distance.
There's a subtle bug, of course, because the first list can be empty while the second one isn't, and the second list can be empty while the first one isn't. And if this is the case, the second body is never hit, and the distinction between different / equal lengths is never made. Because the task of categorizing is split between pattern matching and if-then-else with precedence to pattern matching.
What I do personally to catch problems like these preemptively is to think like this:
When I'm pattern matching on a list (just for example), I have to cover two constructors (1. [], 2. ::), and when I'm pattern matching on two lists, I have to cover the Cartesian product of its constructors (1. [], [], 2. [], ::, 3. ::, [], and 4. ::, ::).
I can count only two patterns/bodies, and none of them aim to cover more than one of my four cases, so I know that I'm missing some.
If there had been a case with variables, I have to ask how many of my common cases it covers, e.g.
fun hammingDistance (x::xs) (y::ys) =
if x = y
then hammingDistance xs ys
else Option.map (fn d => d + 1) (hammingDistance xs ys)
| hammingDistance [] [] = SOME 0
| hammingDistance _xs _ys = NONE
Here there's only three patterns/bodies, but the last one is a catch-all; _xs and _ys match all possible lists, empty or non-empty, except if they're matched by one of the previous patterns first. So this third case accounts for both of 2. [], :: and 3. ::, [].
So I can't simply count each pattern/body once. Some may account for more than one class of input if they contain very general patterns via pattern variables. And some may account for less of the total input space if they contain overly specific patterns via multiple constructors. E.g.
fun pairs (x::y::rest) = (x, y) :: pairs rest
| pairs [] = []
Here x::y::rest is so specific that I'm not covering the case of exactly one element.
I have the following list of sublists
[[1;5;10];
[2;6;11];
[3;7;12]];
I am trying to a create the following list of sublists:
[[1;2;3];
[5;6;7];
[10;11;12]]
The first sublist of the result should containt the first element of each original sublist, second result sublist should contian the second elements of each of the original sublists and so on.
Each sublist contains the same number of elements as the other sublists. The amount of sublists is at least 2.
I was thinking of using List.map but I am not sure what function to apply to each sublist to exctract the needed elements.
This is what I have so far:
let rec compute list =
List.map (fun x -> ) list
Any suggestions are appreciated!
Here you need two recursions (as you would need 2 imbricated loops in an imperative language).
The first recursion should allow you to go through the inputs line, say from 1 to 3, and at each step of this recursion, you will need a second recursion,to go along the full row.
You can either do it all by hand or you can use List.fold_left. (I would use fold for the inner recursion.
I already have this code to match if any numbers in a list match any numbers in the other list. However, I need to modify my recursion so it returns false if the same number is found in the same position on both lists.
For example:
[5,3,4,6,2] is compatible with [3,1,2,2,7]; and [1,3,4,9,2] is incompatible with [4,5,2,9,8] because both lists have a 9 in the 4th position.
Here is the code I have so far:
common_elements([], L) :-
fail.
common_elements([H|T], L) :-
memberchk(H, L), !.
common_elements([H|T], L) :-
common_elements(T, L).
SWI-Prolog example inputs and outputs for current code:
?- common_elements([1,2,3,4],[6,7,8,9]).
false.
?- common_elements([1,2,3,6],[6,7,8,9]).
true.
As with (nearly) all predicates with list processing, you can split your predicate in two types of clauses:
base clauses: in many cases these lists deal with empty lists. Here this is for instance:
compatible([],_).
compatible(_,[]).
inductive clauses: in this case both lists are not empty. In that case you have to compare the heads of the two lists. If not equal, you make a recursive call:
compatible([HA|TA],[HB|TB]) :-
HA \= HB,
compatible(TA,TB).
in the recursive call, you simply use the tails of both lists.
Now merging both clauses:
compatible([],_).
compatible(_,[]).
compatible([HA|TA],[HB|TB]) :-
HA \= HB,
compatible(TA,TB).
You can make it a bit more effecient (and atomic by using a cut):
compatible([],_) :-
!.
compatible(_,[]).
compatible([HA|TA],[HB|TB]) :-
HA \= HB,
compatible(TA,TB).
Demo (swipl):
?- compatible([5,3,4,6,2],[3,1,2,2,7]).
true.
?- compatible([1,3,4,9,2],[4,5,2,9,8]).
false.
I have the following Prolog predicate prototype: solution(+InputVector), where InputVector is a list of values of an unknown length. If all the values in the list are greater than 0, I print out a message. How do I do this?
if you are interested to extend your learning to 'higher order' predicates, consider maplist/2:
3 ?- maplist(<(0), [1,2,3]).
true.
4 ?- maplist(<(0),[0,1,2,3]).
false.
Try checking if the list is [] or [X|Xs], and act accordingly.
You were nearly there. Consider the following (updated thanks to #aBathologist):
1| solution([X]) :-
2| X > 0,
3| !,
4| write_ln('Success!').
5| solution([X|Y]) :-
6| X > 0,
7| solution(Y).
Let's consider how this actually works, line-by-line:
Defines the first clause of the predicate solution/1 which takes a single-element list containing X as an argument.
Tests if item X is a number which is > 0. If not, the predicate will terminate here and fail. Otherwise, Prolog will continue to the next line.
While not strictly necessary, the cut (!) here removes the choice-point Prolog would have generated at (1) given that the second clause on line (6) could also have been executed with the input [X], as this is equivalent to [X|Y] where Y = []. Therefore, this is a so-called 'grue'-cut for efficiency only.
As the list [X] contains elements all greater than zero, the predicate prints a message and suceeds.
Defines the second clause of the predicate solution/1 which takes a list containing one or more items, where X is the head of the list, and Y is the tail (remainder) of the list (which is itself a list which could be empty: []).
Same as line (2).
Proceed to recursively test the remainder of the list, Y.
Note that the above definition assumes that solution/1 must only succeed on non-empty lists of numbers greater than zero. If you wish to permit this predicate to succeed on empty lists, the implementation can be made even simpler:
solution([]) :-
write_ln('Success!').
solution([X|Y]) :-
X > 0,
solution(Y).
In this version, either one of the two clauses of solution/1 is executed based on the argument: the first handles empty lists, and the second handles non-empty lists of numbers which are greater than zero. A cut (!) is not necessary here as the predicate arguments are non-unifiable ([] \= [X|Y]) and Prolog will not generate choice-points for any invocation of the first clause.
I hope this has been helpful, and has made some of the semantics of Prolog syntax clearer for you.
I'd write the predicate like this:
all_greater_than_zero([]).
all_greater_than_zero([H|T]) :-
H > 0,
all_greater_than_zero(T).
I assumed that an empty list was acceptable. If not, you can remove the first clause.
I've just starting working with Prolog and I don't understand how to work with multiple predicates.
For example I have to solve the following problem: Substitute in a list a value with all the elements of another list.
This is the code that I managed to write so far:
domains
elem=integer
list=elem*
predicates
%append to a list already created another list. There are 3 list parameters
%because I don't know other method
append (list,list,list)
%This will search the list (the first one) for the searched element and
%it is it will replace it with the list(the second one). The result will be
%kept in the third list.
add(list,list,elem,list)
goal
add([1,2,3,2,1],[4,5],2,L),
write (L).
clauses
add ([],[_],_,[]).
add ([A|L],L1,E,[A|L2]):-
add(L,L1,E,L2).
add ([E|L],L1,E,L2):-
add(L,L1,E,L2).
append([],[],L2).
append([],[X|L1],[X|L2]):-
append([],L1,L2).
Does your append definition is working? I think should be
append([], L, L).
append([X|Xs], Ys, [X|Zs]):-
append(Xs, Ys, Zs).
The append predicate it's one of the most basic tools in Prolog programming, better to keep the usual behaviour, or to change name...
Instead of add, a better name could be replace_elem_with_list.
To implement it you should iterate, inspecting each element, and when you find a match to what's required to replace append the list instead of copying the element.
Something like
% replace_elem_with_list(ToSearch, Replacement, SoughtElem, Result)
replace_elem_with_list([E|Es], Replacement, E, Result) :-
!, replace_elem_with_list(Es, Replacement, E, Rs),
append(Replacement, Rs, Result).
I'll leave you the other 2 cases that you will need to cover (when element doesn't match and recursion base, which are similar to append)
the result:
?- replace_elem_with_list([1,2,3,4,2,3,4],[a,b],2,L).
L = [1, a, b, 3, 4, a, b, 3, 4].