number_in_month exercise (Error in SML function to build a list of integers from a list of tuples) - tuples

val test1 = [(1,5,3),(3,5,2),(3,4,5)]
fun number_in_month dates_and_month =
case dates_and_month of
(x,y,z)::xs' => y :: number_in_month xs'
This code produces the following error when I run in the REPL with test1:
uncaught exception Match [nonexhaustive match failure]
raised at: hw1pm.sml:28.49
Any clue why?

It did not know what do when the list was empty.
Working code:
fun number_in_month dates_and_month =
case dates_and_month of
[] => []
| (x,y,z)::xs' => y :: number_in_month xs'

Edit: I've tried to make this answer more helpful while preserving the observation that this is probably the most asked SML question on StackOverflow. A total list of the times this question was asked: 1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th, 12th, 13th, 14th, 15th and 16th (not counting this post).
Rather than to answer this question again, a curated version of those are here:
1st, 2nd, 6th, 12th struggle with recursion and infinite recursion. Some attempts include the use of the function null, and others include pattern matching. I'd go with the recommendation to use pattern matching.
3rd, 4th, 5th, 7th, 13th, 14th provide a lot of insight into the general structure of this function. You'll probably learn a bunch more than you asked for by just reading those answers, and since they cover a lot of elementary subjects in the context of a function you're actively working with, this may be very worthwhile.
10th deals with using a mutable reference, so stay away from that one unless you're about to make that same mistake!
11th doesn't actually ask anything, but the author says they have this exercise and then kind of stops dead in their tracks. There's a lesson here and I'm not going to be the one to figure it out.
8th, 9th, 15th and 16th appear to address syntax errors.
Questions asked on this matter subsequent to this answer: 17th (missing else).

Related

How can I calculate the length of a list containing lists in OCAML

i am a beginner in ocaml and I am stuck in my project.
I would like to count the number of elements of a list contained in a list.
Then test if the list contains odd or even lists.
let listoflists = [[1;2] ; [3;4;5;6] ; [7;8;9]]
output
l1 = even
l2 = even
l3 = odd
The problem is that :
List.tl listoflists
Gives the length of the rest of the list
so 2
-> how can I calculate the length of the lists one by one ?
-> Or how could I get the lists and put them one by one in a variable ?
for the odd/even function, I have already done it !
Tell me if I'm not clear
and thank you for your help .
Unfortunately it's not really possible to help you very much because your question is unclear. Since this is obviously a homework problem I'll just make a few comments.
Since you talk about putting values in variables you seem to have some programming experience. But you should know that OCaml code tends to work with immutable variables and values, which means you have to look at things differently. You can have variables, but they will usually be represented as function parameters (which indeed take different values at different times).
If you have no experience at all with OCaml it is probably worth working through a tutorial. The OCaml.org website recommends the first 6 chapters of the OCaml manual here. In the long run this will probably get you up to speed faster than asking questions here.
You ask how to do a calculation on each list in a list of lists. But you don't say what the answer is supposed to look like. If you want separate answers, one for each sublist, the function to use is List.map. If instead you want one cumulative answer calculated from all the sublists, you want a fold function (like List.fold_left).
You say that List.tl calculates the length of a list, or at least that's what you seem to be saying. But of course that's not the case, List.tl returns all but the first element of a list. The length of a list is calculated by List.length.
If you give a clearer definition of your problem and particularly the desired output you will get better help here.
Use List.iter f xs to apply function f to each element of the list xs.
Use List.length to compute the length of each list.
Even numbers are integrally divisible by two, so if you divide an even number by two the remainder will be zero. Use the mod operator to get the remainder of the division. Alternatively, you can rely on the fact that in the binary representation the odd numbers always end with 1 so you can use land (logical and) to test the least significant bit.
If you need to refer to the position of the list element, use List.iteri f xs. The List.iteri function will apply f to two arguments, the first will be the position of the element (starting from 0) and the second will be the element itself.

Extracting list of items between two values in a list - prolog

Say I have a unique list of length 9 of the values between 1 and 9 inclusive in a random order (think sudoku), and I want to extract a the sub-list of the items that occur between the values 1 and 9 (exclusive). IE: between1and9([1,3,5,4,2,9,7,8,6],[3,5,4,2]) should be true.
At the moment I'm trying to use flatten/2, but not having much luck. Here's my current tactic (assuming I enforce List ins 1..9, maplist(all_distinct, List), length(List, 9) elsewhere to keep it tidy here/seperation of concerns):
between1and9(List,Between) :-
flatten([_,[1],Between,[9],_], List);
flatten([_,[9],Between,[1],_], List).
This version fails though when 1 or 9 are at the first or last position in List, or if they're adjacent within List. between1and9([_,1,9,_,_,_,_,_,_],[]) is true, but between1and9([_,1,9,_,_,_,_,_,_],_) is false (and fails when I try to use it as a constraint to solve a bigger problem.)
It seems to be the same problem casuing both failures, flatten doesn't seem to like treating unknowns as empty lists unless they're made explicit somewhere.
I can see why that would potentially be, if flatten could "invent" empty lists in the first argument it would mean an infinite set of solutions for anything in the first argument. Although my full program has other constraints to prevent this, I can understand why flatten might not want to accomodate it.
I can account for the edge cases (pun intended) by matching every permutation with disjunctions (ie: flatten([_,1,B,9,_],L);flatten([_,9,B,1,_],L);flatten([_,1,B,9]);flatten..., And account for the Between as an empty list with: \*above permutations on flatten*\; ( Between = [], (\*permutations for either edge and 1/9*\) )
But that seems to be making an already longwinded solution (10 permutations of flatten in total) even worse (18) so I have two (strongly related) questions:
If I could do the following:
between1and9(L,B) :-
( ( X = 1, Y = 9 ); ( X = 9, Y = 1 ) ),
( ( Z1 = _; Z1 = [] ), ( Z2 = _ ; Z2 = [] ) ),
( B = _; B = [] ),
flatten([Z1,X,B,Y,Z2],L).
I wouldn't have to manually type out each permutation of match for flatten. Unfortunately this and a few variations on it all unilaterally fail. Am I missing somethign obvious here? (I suspect opperator precedence but I've tried a few different versions.)
Or am I doing this completely wrong? The flatten/2 documentation suggests that in most cases it's an anti-pattern, is there a more prolog-ish* way to go about solving this problem? Given all the pitfalls I'm realising as I go through this I'm almost certain there is.
(Sorry, I'm painfully aware that a lot of the terminology I'm using to describe things in this is probably very wrong, I'm only kind of familiar with predicate/formal logic and much more used-to describing control flow type programming. Even though I understand logic programming in practice reasonably well I'm struggling to find the language to talk about it robustly yet, I will amend this question with any corrections I get.)
Some background: I'm new to prolog and testing out my understanding by trying to extend one of the many sudoku solvers to solve a strange variety of sudoku I found in some puzzles I printed out years ago where you're shown the sum of all the numbers that appear between the 1 and the 9 in any given row or column as an extra hint, it's kind of like a mix of sudoku and picross. The solver as it stands now is on swish: SumSudoku(swish). Although it may be a mess when you get to it.
*Corollary quesiton: is there a prolog version of the word "pythonic?"
You could use good old append/3 for this. Is it possible that you wanted append/3 all along but somehow thought it is called flatten?
For the "1 comes before 9" case, you'd write:
between_1_and_9(List, Sublist) :-
append(_, [1|Rest], List),
append(Sublist, [9|_], Rest).
You need to swap 1 and 9 for the "9 comes before 1" case.
This also leaves a "spurious choice point" (Thank you #PauloMoura for the comment). Make sure to get rid of it somehow.
As for "Pythonic" (and this comes from a recovering Pythonista), I can only say, rest assured:
There is always more than one obvious way to do it in Prolog.
You don't even have to be Dutch.

Prolog - Check number of occurences doesn't work as expected

In Prolog:
I have the following function that counts the occurences of a certain element in a list:
%count(L:list,E:int,N:int) (i,i,o)
count([],_,0).
count([H|T],E,C):-H == E,count(T,E,C1),C is C1+1.
count([_|T],E,C):-count(T,E,C).
I tested it and it works well. But here comes the problem, I have another function that has to check if "1" occurs less than 2 times in a list.
check(L):-count(L,1,C),C<2.
Whenever I try to check the list [1,1,1,1] for example, the result I get is "true", which is wrong, and I have no idea why. I tried to make some changes, but the function just won't work.
Improve your testing habits!
When testing Prolog code don't only look at the first answer to some query and conclude "it works".
Non-determinism is central to Prolog.
Quite often, some code appears to be working correctly at first sight (when looking at the first answer) but exhibits problems (mainly wrong answers and/or non-termination) upon backtracking.
Coming back to your original question... If you want / need to preserve logical-purity, consider using the following minimal variation of the code #Ruben presented in his answer:
count([],_,0).
count([E|T],E,C) :-
count(T,E,C1),
C is C1+1.
count([H|T],E,C) :-
dif(H,E),
count(T,E,C).
dif/2 expresses syntactic term inequality in a logical sound way. For info on it look at prolog-dif!
It happens because count([1,1,1,1],1,1) is also true! In your last count it can also be matched when H does equal E. To illustrate this, use ; to make prolog look for more answers to count([1,1,1,1],1,R). You'll see what happens.
count([],_,0).
count([E|T],E,C):-
count(T,E,C1),
C is C1+1.
count([H|T],E,C):-
H \= E,
count(T,E,C).
check(L) :-
count(L,1,C),
C < 2.
?- check([1,1,1,1,1]).
false
?- check([1]).
true
second and third clauses heads match both the same sequence. As a minimal correction, I would commit the test
count([],_,0).
count([H|T],E,C):-H == E,!,count(T,E,C1),C is C1+1.
count([_|T],E,C):-count(T,E,C).

Prolog list unification

I am trying to further my understanding of Prolog, and how it handles list unification. So I am stuck with this example, that I know the answer as I execute the code, but I cannot understand how it works.
[X,a,X,f(X,a)|Y] = [Z,Z|Y]
The answer is:
X=Z
Z=a
Y=_
L=[a,f(a,a)|Y]
I know that the head unifies with the other head, so if I make some changes, like these:
let C=[X,a,X,f(X,a)]
let D=[Z,Z]
and the unification should go this way:
[C|Y]=[D|L]
so Y must be equal to L, not _, right? Can someone explain me this better and correct my mistake?
There's nothing special or unique about lists. A list is just the data structure ./2. Prolog's list notation is just syntactic sugar on top of that. In a nutshell:
[] is an atom and denotes the empty list.
[a] is exactly equivalent to .(a,[]).
[a,b] is exactly equivalent to .(a,.(b,[])).
etc.
The head/tail construct [Head|Tail] is likewise syntactic sugar:
[H|T] is exactly equivalent to .(H,T).
Replace the list notation with the dot notation and your predicate will work exactly the same. Just not as convenient.
See my answer here for details.
Please show your actual interraction with the interpreter.
For example,
$ swipl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.1.36-18-ga5e157c)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- [X,a,X,f(X,a)|Y] = [Z,Z|Y].
X = Z, Z = a,
Y = [a, f(a, a)|Y].
(Note that Y is now a cyclic term.)
If you showed what it is that you actually doing, it might be easier to help you. Just edit your question.

Declarative interpretation of this program that says if an element belongs to a list

From what I have understood the declarative paradigm indicate what is important to reach the solution and not how reach it but, being accustomed to think procedurally, I often make confusion...
So the solution is this one:
mymember(X, [X|_]).
mymember(X,[_|T]) :- mymember(X,T).
This is my declarative interpretation of this simple program:
1) X belong to the list if it is TRUE that X is the Head of this list (if the head element of the list unifies with the X element that I would know if is in the list)
2) If the first fact is not true (X don't unifies with the first list element) the program try to execute the second rule (and maybe here I have some interpretation problem). This rule say that: the head is true if the body of the rule is true)
The head of rule say that: X belongs to the TAIL of the list (I use an anonymous variable using the _ character to say that don't care of the first element of the list)
So this rule say that: It is TRUE that the X element belong to list without its head if it is TRUE that the X element belong to the tail of the list
Is it a correct declarative and logic interpretation of this program or I am missing something?
You're reading them as exclusive-or, but they're actually inclusive-or. Both 1) and 2) are correct, minus the connective "if the first fact is not true". It's not necessary for 1) to be false for 2) to hold. In other words, it can be true that X is both the head of the list and present in the tail of the list (for instance mymember(a, [a, b, a]).
Edit: responding to your comment.
There's a language barrier issue here, so let me try answering your question with yes and no.
Yes, that using ; produces another answer is evidence that Prolog was able to compute alternative answers. In one sense, ; triggers backtracking manually, but in another sense it is Prolog asking you if this is the answer you wanted, and then you're able to say "yes" or "no." When you say ; you're telling Prolog, in essence, "this isn't the right answer." But this is not the only way to trigger backtracking; in fact, most of the time you won't trigger it manually at all.
For instance, let's look at this:
even_member(X, L) :- member(X, L), 0 is X mod 2.
?- even_member(X, [1,5,17,23,4,19]).
X = 4 ;
false.
So here I defined a predicate that says, declaratively, X is an even_member of L if X is a member of L and X mod 2 = 0. When I used the predicate, we got the answer X = 4. We then pressed ; to say, this isn't the right answer, and Prolog said there are no more answers. But internally, member(X, L) backtracked 5 times before it found an element that satisfied the second part of the predicate--in other words, the statement 0 is X mod 2 tells Prolog that 1, 5, 17 and 23 are "wrong" the same way we do by pressing ; interactively. When we said we wanted another answer, we engaged the same machinery, so Prolog went back to member(X, L), found 19, and then found that 19 is not divisible by two and gave up.
Prolog backtracked six times, five of those times just to get the one answer. We only asked it to backtrack once, and it happened that it was the last possibility so it didn't backtrack again.
Let me try:
mymember(X, [X|_]).
X is a member of the list if it's the first element of the list
mymember(X,[_|T]) :- mymember(X,T).
X is a member of the list if it's a member of the rest of the list.
Suppose I give you a stack of (paper) programmer resumes and say "see if there is a programmer who knows Prolog among these"
What do you do? You look at the top resume. If that programmer knows Prolog, you're done.
If not, then the only way there can be such a resume is if it's in the rest of the stack.
point 2) doesn't hold: Prolog will try each rule searching for a solution.
But it will follow a strictly specified order searching in your database, resulting in a depth first search of the solution space.
I would read
X is a member of a list if it is the first element (i.e. unify the head, clause 1), or is a member of the tail (clause 2).