Two conditional based replace function over same list in prolog? - list

I need to replace elements in a list based on its value, for certain type of value I need to execute one kind of replacement and for the second one I have an auxiliar function that returns the element that I want to use as replacement, so:
%receives a character (a 'code') and returns a list with other characters (the 'value' of that code)
auxiliarFunction(Char, Response)
An exampleof what I need to do:
I neeed a function receiving a list of numbers and letters. If the letter 'a' appears, I want to replace it with the character * and concat it to the Res variable, but if it is not 'a' I need to call auxiliarFunction and concat Response to Res (let's assume that it's going to be the name the number as a list of letters, this is just an example because the real auxiliar function is complex, but the output it is simple).
Pseudo code:
replaceChars([], [])
replaceChars([X|Xs], Res)
% if x == a then Res will have [*] (concat '*' to Res)
% else auxiliarFunction(X, Response) and concat Response to Res (Response will be a list)
% replaceChars(Xs, Res) make recursion call
For example, a valid input could be [2,a,2,a] and the output (Res) it should be [t,w,o,*,t,w,o,*].
How can I make these two conditional replacement-functions over the same list?

if A then B else C is written in prolog as A -> B ; C
replaceChars([], []).
replaceChars([X|Xs], Res) :-
replaceChars(Xs, Res1),
( X = a
-> Res = [* | Res1]
; auxillaryFunction(X, Response),
append(Response, Res1, Res)
).
I think the validity of input should be checked seperately, isValid(Xs), replaceChars(Xs, Ys).
isValid([_]).
isValid([a, X | Xs]) :- dif(a, X), isValid([X|Xs]).
isValid([X, a | Xs]) :- dif(a, X), isValid([a|Xs]).

Related

SMLNJ function that returns as a pair a string at the beginning of a list

So im really confused as i am new to sml and I am having trouble with syntax of how i want to create my function.
the instructions are as follows...
numberPrefix: char list → string * char list
Write a function named numberPrefix that returns (as a pair) a string representing the digit characters at the
beginning of the input list and the remaining characters after this prefix. You may use the Char.isDigit and
String.implode functions in your implementation.
For example,
numberPrefix [#"a", #"2", #"c", #" ", #"a"];
val it = ("", [#"a", #"2", #"c", #" ", #"a") : string * char list
numberPrefix [#"2", #"3", #" ", #"a"];
val it = ("23", [#" ", #"a"]) : string * char list
Here is my code so far...
fun numberPrefix(c:char list):string*char list =
case c of
[] => []
|(first::rest) => if isDigit first
then first::numberPrefix(rest)
else
;
I guess what i am trying to do is append first to a seperate list if it is indeed a digit, once i reach a member of the char list then i would like to return that list using String.implode, but I am banging my head on the idea of passing in a helper function or even just using the "let" expression. How can I essentially create a seperate list while also keeping track of where i am in the original list so that I can return the result in the proper format ?
First of all, the function should produce a pair, not a list.
The base case should be ("", []), not [], and you can't pass the recursive result around "untouched".
(You can pretty much tell this from the types alone. Pay attention to types; they want to help you.)
If you bind the result of recursing in a let, you can access its parts separately and rearrange them.
A directly recursive take might look like this:
fun numberPrefix [] = ("", [])
| numberPrefix (cs as (x::xs)) =
if Char.isDigit x
then let val (number, rest) = numberPrefix xs
in
((str x) ^ number, rest)
end
else ("", cs);
However, splitting a list in two based on a predicate – let's call it "splitOn", with the type ('a -> bool) -> 'a list -> 'a list * 'a list – is a reasonably useful operation, and if you had that function you would only need something like this:
fun numberPrefix xs = let val (nums, notnums) = splitOn Char.isDigit xs
in
(String.implode nums, notnums)
end;
(Splitting left as an exercise. I suspect that you have already implemented this splitting function, or its close relatives "takeWhile" and "dropWhile".)

Fold-add all items in List, using Prolog

I'm trying to write a function that recursively adds the first two items in a List, and returns when one item remains.
Example:
addList([1,2,3,4], X)
x = [10]
(Steps here would be: [1,2,3,4] -> [3,3,4] -> [6,4] -> [10] )
This is what I have:
addList([],[]).
addList([H|[H2|T]], []) :- L is H+H2, addList(T, [L|T]).
addList([H|T], [H2|_]) :- L is H+H2, addList(T, [L|T]).
In my mind, this would do something like the following:
addList([1,2,3,4], X).
L=1+2 --> addList([3,4], [3,3,4])
L=3+3 --> addList([4], [6, 4])
L=6+4 --> addList([], [10])
This actually causes an error - "Arguments are not sufficiently instantiated"
If I make the first addList into addList([],[_])., it'll output X = [] . first, then have the same error if I use ; to continue.
It should end in false.
(After having the chain of X = [1,2,3,4] ; X = [3,3,4] ; X = [6,4] ; X = [10] ; false.
First, note that you can write [H|[H2|T]] equivalently as [H,H2|T].
Also, as far as I know in Prolog the preferred style is to use snake_case instead of camelCase.
add_list([H1,H2|T], []) :- ...
In the above clause, you already unifiy the second term with the empty list, and what happens in ... is just a way of checking if the relationship holds. The L that occurs in the body is only a local variable; likewise, the recursive call to add_list is not used to compute the "result" (the second parameter).
You expect the result to always be a singleton list containing the total sum of your values, except if the list is empty (in which case the result is empty). The base cases are then:
add_list([], []).
add_list([N], [N]).
The general case is necessarily something like:
add_list([H1,H2|T], [Sum]) :- ...
And you have to expression the recursive relationship in terms of H1, H2, T and Sum. In fact until you reach a base case you are likely to only pass down the second argument unmodified, so you do not need to write [Sum] explicitly, you could just write Res:
add_list([H1,H2|T], Res) :-
...,
add_list(..., Res).

number_in_month exercise (Iteration over multiple lists in SML)

I am having two lists in SML, lets say list A [(a,b,c),(d,e,f)] and list B [b,e]. I want to count how many occurrence of each item in B that matches the second element of each triple in A. The output should be 2. Because b and e each occurs once in A.
This is my code so far but my counter is always set to 0 when I move from one element to another in B. I know in Java this will just be a simple double for loop.
fun number_in_months (d : (int * int * int ) list, m : (int) list) =
if null m then 0
else if null d then number_in_months(d, tl m)
else if (#2(hd d)) = (hd m) then 1 + number_in_months (tl d, m)
else number_in_months(tl d, m)
The code is not accumulating a value between recursive calls. There may be other logic errors too.
Accumulating a value using recursion and functions is a common pattern which you can read more about here. It's essence is to deconstruct a list using head and tail until the list is empty and accumulate some value at each call. The sum function below is a simple example to show this. This could be adapted to your example to accumulate acc when b or e are found in list A.
fun sum(numbers: (int) list) =
let fun sumR(numbers: (int) list, acc: int) =
if null numbers
then acc
else
sumR(tl numbers, hd numbers + acc)
in
sumR(numbers, 0)
end
Running on [1,2,3] gives:
val sum = fn : int list -> int
- sum([1,2,3]);
val it = 6 : int
Note I am intentionally vague with this answer since this is a question regarding Coursera homework for the Programming Languages class.
As you mention, it would be a nested/double loop in any imperative programming language. What you are actually missing is the second loop.
Your "inner" loop goes through all elements of d, and when this is done, your "outer" loop tries to pop the top element of m and start all over, as seen from this line of your code:
else if null d then number_in_months(d, tl m)
However as you can see, you have just tested the list d to be empty and you supply this (exact same list) to your recursive call on the tail of m, which will then fall in this same case for each successive call until m is also empty and you return 0.
Thus what you are missing is to "keep a copy" of the original input list m. This can be done in various ways, but an inner (helper) function is properly the most used one and it even "looks" like a nested loop
fun number_in_months (d, m) =
let
fun nim' ([], y::ys) = nim (d, ys) (* 1 *)
| nim' (_, []) = 0 (* 2 *)
| nim' ((_, x2, _) :: xs, yss as (y::ys)) = ... (* 3 *)
in
nim'(d, m)
end
Using pattern matching the above code gets much simpler and less error prone. In case 1, the "inner" loop has gone through all elements in d, thus the recursive call using d from the outer function which is not changed at any time. In case 2, the "outer" loop has gone through all elements of m and we return 0 (the neutral element of addition). In case 3 we do the actual work. Here pattern matching is used such that we don't need to enforce the type of the argument and we don't need to pull out the 2nd element of the triple, we already have it in the variable x2. All that is needed is to do the computation and make a recursive call with xs and yss.
When doing it this way, the inner (helper) function is using a "copy" of the original input list d and stepping through its elements (potentially modifying it), but we always got a reference to the original input list, which we can use if/when needed.

List of all the elements in sublist in Prolog

I need to write a predicate f(L,R) that succeeds if and only if L is a list containing all terms in R that are not lists.
For example:
f(L,[1,2,3,[4,5,6],[[7,8,9]],[]]).
Should give:
L = [1,2,3,4,5,6,7,8,9]
I wrote a predicate that gives the following result instead:
L = [1,2,3,4,5,6,7,8,9,[]]
Empty lists should not be present in the result. My predicate is the following:
f([],[]).
f(V,[H|T]):- H = [_|_] -> append(L,R,V),
f(L,H), f(R,T),!;
V = [H1|T1], H1=H, f(T1,T).
I have two doubts. First of all, the empty lists should not be present in the result. Also I don't know why it does not work if I don't put the cut (!). In fact, if I don't put the cut it gives me the result as above, but if I ask for another result it loops forever. I really don't understand why this should loops.
To remove the empty list, handle that case (discard it).
About the loop: I think the cause could be that you're calling append(L,R,V) with all arguments not instantiated: move append after the recursive calls.
Finally, maybe you don't use rightly the 'if then else' construct: I've indented using the usual SWI-Prolog source style, using indentation to highlight 'sequential' calls
f([], []).
f(V, [H|T]) :-
( H = [] % if H = []
-> f(V, T) % then discard
; H = [_|_] % else if H is list
-> f(L,H), % flat head
f(R,T), % ...
append(L,R,V)
; V = [H|T1], % else
f(T1,T) % ...
).

managing lists in prolog

Im new to Prolog and was looking for some assistance. What i am trying to do is basically get a list L consisting of elements that repeat at least twice in a given list L'
Example
L'=[1,2,1,3,4,3,2] => L=[1,2,3].
So far I am able to compute the occurrence of every consecutive variables
% pack(L1,L2) :- the list L2 is obtained from the list L1 by packing
% repeated occurrences of elements into separate sublists.
% (list,list) (+,?)
pack([],[]).
pack([X|Xs],[Z|Zs]) :- transfer(X,Xs,Ys,Z), pack(Ys,Zs).
% transfer(X,Xs,Ys,Z) Ys is the list that remains from the list Xs
% when all leading copies of X are removed and transfered to Z
transfer(X,[],[],[X]).
transfer(X,[Y|Ys],[Y|Ys],[X]) :- X \= Y.
transfer(X,[X|Xs],Ys,[X|Zs]) :- transfer(X,Xs,Ys,Zs).
% encode(L1,L2) :- the list L2 is obtained from the list L1 by run-length
% encoding. Consecutive duplicates of elements are encoded as terms [N,E],
% where N is the number of duplicates of the element E.
% (list,list) (+,?)
encode(L1,L2) :- pack(L1,L), transform(L,L2).
transform([],[]).
transform([[X|Xs]|Ys],[[N,X]|Zs]) :- length([X|Xs],N), transform(Ys,Zs).
which will return the following list of touples
?- encode([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).
X = [[4,a],[1,b],[2,c],[2,a],[1,d][4,e]]
But there still remains the problem of building a list that will contain distinct elements that repeat at least twice.
If anyone can help me or point me in the general direction that would be great.
Thanks in advance
an element E of list L should:
be a member of list L',
be a member of list L'' where L'' is list L' if we remove element E.
check select/3, member/2, findall/3 and/or setof/3
You could write a procedure:
% E it's the list of are elements from L that repeat at least twice
elements_that_repeat_at_least_twice(L, E) :-
elements_that_repeat_at_least_twice(L, [], E).
elements_that_repeat_at_least_twice([H|Ls], Dupl, E) :-
...
In elements_that_repeat_at_least_twice the added list Dupl will keep each element you verify it's present multiple times. Examine each element of L, using [H|Ls].
Use memberchk/2 to verify if H is in L: then it's at least duplicate. If it's not yet in Dupl, add to it, and recurse. Remember to write the recursion base case (stop at empty list []).
Now I see you have added some code: then I complete suggestion:
elements_that_repeat_at_least_twice([], Dupl, Dupl).
elements_that_repeat_at_least_twice([H|Ls], Dupl, E) :-
( memberchk(H, Ls)
-> ( \+ memberchk(H, Dupl)
-> Dupl1 = [H|Dupl]
; Dupl1 = Dupl
)
; Dupl1 = Dupl
),
elements_that_repeat_at_least_twice(Ls, Dupl1, E).
Remember to reverse the list of duplicates when done.