/* Define a Prolog predicate replicate/3 which corresponds to
* the Haskell function of the same name, except that the numeric
* argument is expressed symbolically.
*
* For example, replicate(s(s(s(0))),a,[a,a,a]) should be satisfied.
*/
So far I've come to this solution:
replicate(0,_,[]).
replicate(X,Y,[Y|Z]) :- replicate(p(X),Y,Z).
but the problem is that the s(s(s(0))) is not getting reduced by the pred function. it results into p(p(p(s(s(s(0))))))
could you guys help me out?
This is Haskell's replicate coded with the (deprecated) n+k patterns:
replicate 0 _ = []
replicate (n+1) a = a : x where x = replicate n a
This directly corresponds to the Prolog definition:
replicate(0, _, []).
replicate(s(N), A, [A | X]) :- replicate(N, A, X).
We just move the result into the arguments list, and make it the last argument to the predicate:
x = replicate n a -----> replicate(N, A, X).
The pattern matching is the same. What's not the same, is that Prolog is not an expression-oriented language. There are no expressions which get evaluated before being used as arguments in the next function call; instead, there are terms which are auto-quoted, always, used as is as arguments to predicates.
Related
Horner's rule is used to simplify the process of evaluating a polynomial at specific variable values. https://rosettacode.org/wiki/Horner%27s_rule_for_polynomial_evaluation#Standard_ML
I've easily applied the method using SML, to a one variable polynomial, represented as an int list:
fun horner coeffList x = foldr (fn (a, b) => a + b * x) (0.0) coeffList
This works fine. We can then call it using:
- val test = horner [1.0, 2.0, 3.0] 2.0;
> val test = 17.0 : real
Where [1.0, 2.0, 3.0] is the list representing the polynomial coefficients, 2.0 is the value of the variable x, and 17.0 is the result of evaluating the polynomial.
My problem is as such: We have a two variable polynomial represented by an (int list list). The nth item in a high-level list will represent all the polynomial terms containing y^n, and the mth item in a low-level list will represent all the polynomial terms containing x^m.
For example: [[2],[3,0,0,3],[1,2]] is the polynomial
( 2(x^0)(y^0) ) +
( 3(x^0)(y^1) + 0(x^1)(y^1) + 0(x^2)(y^1) + 3(x^3)(y^1) ) +
( 1(x^0)(y^2) + 2(x^1)(y^2) )
The function needs to return the value of the polynomial at the specified x and y.
I've tried various methods using the mlton compiler.
First I tried a nested foldr function:
fun evalXY (z::zs) x y =
foldr
(fn (s, li:list) =>
s + ((foldr (fn(a, b) => a + b*x) 0 li)*y)
)
0
z:zs
You can see that I'm trying to use "s" as an accumulator, like "a" was used in the single variable example. Since each element being processed by foldr needs to be "foldr'ed" itself, i call foldr again in the function describing the outer foldr. I know hat this inner foldr works fine, I proved it above. *My problem seems to be that I cant access the element of the list that the outer foldr is on to pass that list into the inner foldr. >See where I use li in the inner foldr, thats my issue. *
Then i tried applying my single variable function to map. I came across the same issue:
fun evalXY (z::zs) x y =
map
(foldr (fn(a, b) => a + b*x) 0 ???)
z:zs
*With this attempt, i know that im getting back a list of ints. I put in an int list list, in which the inner lists were processed and returned to the outer list as ints by foldr. After this i would foldr again to apply the y value to the polynomial.
The function here should look like :: fn evalXY : (int list list) * int * int) -> ... -> int list *
I am new to SML, so maybe i'm missing something fundamental here. I know this is a functional programming language, so I'm trying to accumulate values instead of altering different variables,
You're very close. Let's begin by formalizing the problem. Given coefficients C as a nested list like you indicated, you want to evaluate
Notice that you can pull out the s from the inner sum, to get
Look closely at the inner sum. This is just a polynomial on variable x with coefficients given by . In SML, we can write the inner sum in terms of your horner function as
fun sumj Ci = horner Ci x
Let's go a step further and define
In SML, this is val D = map sumj C. We can now write the original polynomial in terms of D:
It should be clear that this is just another instance of horner, since we have a polynomial with coefficients . In SML, the value of this polynomial is
horner D y
...and we're done!
Here's the final code:
fun horner2 C x y =
let
fun sumj Ci = horner Ci x
val D = map sumj C
in
horner D y
end
Isn't that nice? All we need is multiple applications of Horner's method, and map.
Your second approach seems to be on the right track. If you have already defined horner, what you need to do is to apply horner to the result of mapping horner applied to inner list x over the outer list, something like:
fun evalXY coeffLists x y = horner (map (fn coeffList => horner coeffList x) coeffLists) y
You could replace the two calls to horner by the corresponding folds, but it would be much less readable.
Note that if you reverse the order of the two parameters in horner then you can shorted evalXY:
fun horner x coeffList = foldr (fn (a, b) => a + b * x) (0.0) coeffList
fun evalXY x y coeffLists = horner y (map (horner x) coeffLists)
The point being that the way currying works, if you use this second order then horner x is already a function of coeffList so you no longer need the anonymous function fn coeffList => horner coeffList x. The moral of the story is that when defining a curried function, you should think carefully about the order of the parameters since it will make some partial applications easier to create than others.
By the way, SML is fussy. In your discussion of horner you said that you would call it like horner list 2. It would need to be horner list 2.0. Similarly, in your second attempt, using 0 rather than 0.0 is problematic.
I try to define function with the following protocol:
[(1,2), (6,5), (9,10)] -> [3, 11, 19]
Here is what I have now:
fun sum_pairs (l : (int * int) list) =
if null l
then []
else (#1 hd(l)) + (#2 hd(l))::sum_pairs(tl(l))
According to type checker I have some type mismatch, but I can't figure out where exactly I'm wrong.
This code runs in PolyML 5.2:
fun sum_pairs (l : (int * int) list) =
if null l
then []
else ((#1 (hd l)) + (#2 (hd l))) :: sum_pairs(tl l)
(* ------------^-------------^ *)
The difference from yours is subtle, but significant: (#1 hd(l)) is different from (#1 (hd l)); the former doesn't do what you think - it attempts to extract the first tuple field of hd, which is a function!
While we're at it, why don't we attempt to rewrite the function to make it a bit more idiomatic? For starters, we can eliminate the if expression and the clunky tuple extraction by matching on the argument in the function head, like so:
fun sum_pairs [] = []
| sum_pairs ((a, b)::rest) = (a + b)::sum_pairs(rest)
We've split the function into two clauses, the first one matching the empty list (the recursive base case), and the second one matching a nonempty list. As you can see, this significantly simplified the function and, in my opinion, made it considerably easier to read.
As it turns out, applying a function to the elements of a list to generate a new list is an incredibly common pattern. The basis library provides a builtin function called map to aid us in this task:
fun sum_pairs l = map (fn (a, b) => a + b) l
Here I'm using an anonymous function to add the pairs together. But we can do even better! By exploiting currying we can simply define the function as:
val sum_pairs = map (fn (a, b) => a + b)
The function map is curried so that applying it to a function returns a new function that accepts a list - in this case, a list of integer pairs.
But wait a minute! It looks like this anonymous function is just applying the addition operator to its arguments! Indeed it is. Let's get rid of that too:
val sum_pairs = map op+
Here, op+ denotes a builtin function that applies the addition operator, much like our function literal (above) did.
Edit: Answers to the follow-up questions:
What about arguments types. It looks like you've completely eliminate argument list in the function definition (header). Is it true or I've missed something?
Usually the compiler is able to infer the types from context. For instance, given the following function:
fun add (a, b) = a + b
The compiler can easily infer the type int * int -> int, as the arguments are involved in an addition (if you want real, you have to say so).
Could you explain what is happening here sum_pairs ((a, b)::rest) = (a + b)::sum_pairs(rest). Sorry for may be dummy question, but I just want to fully understand it. Especially what = means in this context and what order of evaluation of this expression?
Here we're defining a function in two clauses. The first clause, sum_pairs [] = [], matches an empty list and returns an empty list. The second one, sum_pairs ((a, b)::rest) = ..., matches a list beginning with a pair. When you're new to functional programming, this might look like magic. But to illustrate what's going on, we could rewrite the clausal definition using case, as follows:
fun sum_pairs l =
case l of
[] => []
| ((a, b)::rest) => (a + b)::sum_pairs(rest)
The clauses will be tried in order, until one matches. If no clause matches, a Match expression is raised. For example, if you omitted the first clause, the function would always fail because l will eventually be the empty list (either it's empty from the beginning, or we've recursed all the way to the end).
As for the equals sign, it means the same thing as in any other function definition. It separates the arguments of the function from the function body. As for evaluation order, the most important observation is that sum_pairs(rest) must happen before the cons (::), so the function is not tail recursive.
I have two predicates in Prolog, the first one does return a correct dot product of two lists(vectors w/e) ... the second is when you take a list times a list of lists(matrix) which will return a list. The second one fails when I try to pass anything such as ([1,2],[[3,4],[5,6],[7,8]], X). Anyone well versed in Prolog see my mistake? I am kinda stuck since tracing and prolog itself just returns a fail all the time.
getDotProd([],[],0.0).
getDotProd([H1|T1],[H2|T2], N):-
getDotProd(T1,T2,N1),
N is N1 + (H1 * H2).
vecTimesMatrix(_,[[]],[]).
vecTimesMatrix([List], [MH|Mtail],[N]):-
N is getDotProd(List, MH, _),
vecTimesMatrix(List, Mtail, N).
Updated Code thus far now:
getDotProd([],[],0.0).
getDotProd([H1|T1],[H2|T2], N):-
getDotProd(T1,T2,N1),
N is N1 + (H1 * H2).
vecTimesMatrix([],[[]],[]).
vecTimesMatrix([List], [MH|Mtail],[N]):-
getDotProd(List, MH, N),
vecTimesMatrix(List, Mtail, N).
Your remaining problem is in your vecTimesMatrix predicate:
vecTimesMatrix([],[[]],[]).
vecTimesMatrix([List], [MH|Mtail],[N]):-
getDotProd(List, MH, N),
vecTimesMatrix(List, Mtail, N).
Issues:
In the second clause, the first argument is given as [List] which would imply a list of a single element (List). Subsequent calls to getDotProd and vecTimesMatrix in the clause indicate that this should simply be List.
In the second clause, the third argument is shown simply as a list of one argument: [N]. So the third argument never "builds" a list. Additionally, the recursive call to vecTimesMatrix has N as its third argument, and that argument had already been instantiated by the prior query to getDotProd as the dot product of the vector List and the vectory MH. Logically, the recursive call should be saying that the vector product of List with Mtail is the tail of the final product.
The base case assumes that the first argument reduces to [], but this is not so. List always remains as-is throughout the recursive process. So instead of [] you should have _ (it will keep its value, but you don't care about it in the base case).
The base case has as a second argument [[]], but that's not the correct form for an empty list. That's actually a list consisting of one element, that element being the empty list. In reality, even though the second argument is a "list of lists", the empty list is still [].
Putting it all together (and renaming predicates per de facto conventions using underscores rather than camel case):
get_dot_prod([], [], 0.0). % Dot product of empty vectors is 0.0
% (Dot prod of vectors of unequal length
% is not defined and will fail)
get_dot_prod([H1|T1], [H2|T2], N) :- % N is dot product of [H1|T1] [H2|T2] if...
get_dot_prod(T1, T2, N1), % N1 is dot product of T1 T2, and
N is N1 + (H1 * H2). % N is N1 + (H1*H2) [evaluated]
vec_times_matrix(_, [], []). % Product of any vector with
% empty matrix is empty
vec_times_matrix(List, [MH|Mtail], [N|Ntail]):-
% [N|Ntail] is List x [MH|Mtail] if...
get_dot_prod(List, MH, N), % N is dot product of List and MH, and
vec_times_matrix(List, Mtail, Ntail). % Ntail is List x Mtail
This will yield:
| ?- vec_times_matrix([1,2],[[1,0],[0,1]], M).
M = [1.0,2.0] ? a
no
| ?- vec_times_matrix([1,2],[[1,0],[0,1],[1,1]], M).
M = [1.0,2.0,3.0] ? a
(1 ms) no
I added the comments in the code above to illustrate, in a simple way, how to think of the prolog predicate logic, which aids in defining them. As was pointed out already, the prolog "predicate" doesn't act as a "function". It describes a logical relation between entities which will either succeed or fail.
Once you learn to think how prolog thinks (relationally), you'll find it more enjoyable. :)
There are several problems in your code. First, you define both getDotProd/4 and getDotProd/3 predicates. The first one is a typo. I.e. you base case for the getDotProd/3 predicate have a duplicated argument and it should be:
getDotProd([], [], 0).
Second, in the second predicate, vecTimesMatrix/3, you have a goal, a call to the built-in predicate is/2, that will cause an exception:
N is getDotProd(List, MH, _)
You cannot define your own functions on standard Prolog. You need to replace that goal with:
getDotProd(List, MH, N)
There are other problems but this should help you progress.
I'm trying to write an element handling function in Prolog. It's almost the same as the prolog predicate member/2 but it must do the job in a different way. For being specific; I must say the member/2 predicate function is this:
member(X, [X|_]).
member(X, [_|Tail]) :-
member(X,Tail).
When you give a query for example: member(X, [1,2,3]).
It gives you X = 1; X = 2; X = 3; in this order for all redo's. I want an element function almost the same. I want the same result with the member function when I give a query like this:
element(X, (1,2,3)).
The difference is just parenthesis instead of bracekts like these : []
In order to do this I tried that:
element(X, (X,_)).
element(X, (_,Tail)) :-
element(X,Tail).
Which is exactly the same as member/2 predicate function implementation. But this doesn't work because it doesn't giving the last element which is X=3.
So I added one more fact that is:
element(X, X).
But this doesn't work either because (obviously) it is giving unnecessary answer with real elements like these:
X=(1,2,3)
X=(2,3)
How can I handle this?
Seems that a cut can solve your problem:
element(X, (X, _)).
element(X, (_, Tail)) :-
!, element(X, Tail).
element(X, X).
test:
?- element(X, (1,2,3)).
X = 1 ;
X = 2 ;
X = 3.
?- element(2, (1,2,3,2)).
true ;
true.
Terms like (1,2,3) in Prolog have commas as their primary functor. Probably you want to use operator univ, denoted by infix =.., or its close relations functor/3 and arg/3 to pick apart these tuples.
I am working on a scenario in Prolog (eclipse) wherein I need a list structure to be reformatted.
I have a list of the form:
MyList = [a,b,c].
I was trying to see if I can flatten the list to a single element with all the commas replaced with the + operator.
So my result list would look like:
ResultList = [a+b+c]
which is a single element list. The length of the initial list is arbitrary.
I know prolog is not suited for such operations, but can this be done?
here it is, in standard Prolog. I think there should be no difference with Eclipse:
list_to_op([X,Y|T], [R]) :-
list_to_op(T, X+Y, R).
edit: bug noted by false
list_to_op([X], [X]).
list_to_op([X], R, R+X).
list_to_op([X|T], R, Q) :-
list_to_op(T, R+X, Q).
test:
?- list_to_op([a,b,c],X).
X = [a+b+c] .
The accumulator is required to give the appropriate associativity: the simpler and more intuitive definition
list_to_op1([X], X).
list_to_op1([X|R], X+T) :-
list_to_op1(R, T).
gives
?- list_to_op1([a,b,c],X).
X = a+ (b+c) .
If evaluation order is important, use list_to_op.
edit:
there is a bug: list_to_op([a,b],X) fails.
here the correction, as often happens, it's a simplification:
list_to_op([], R, R).
list_to_op([X|T], R, Q) :-
list_to_op(T, R+X, Q).
This may help
flatten_list(A,[B]) :- flatten_list_inner(A,B).
flatten_list_inner([A],A).
flatten_list_inner([H|T],H+Y) :- flatten_list_inner(T,Y).
The output is slightly different from what you wanted. It is currently [a + (b + c)]
How about this non-recursive version..
list_to_op(L, Res) :-
concat_atom(L, '+', Atom),
Res = [Atom].
?- list_to_op([a,b,c], X).
X = ['a+b+c'].
Edit: This works in Swi-prolog.. not sure about Eclipse.