Lookup function of Hash Table in SML - hashtable

I was given an assignment to write a lookup function for this hashtable datatype in SML;
datatype 'a ht = table of (int * ('a list)) list;
which returns nil if the table is empty and/or the key doesn't exist the table.
The function is supposed to be this
val lookup = fn : int -> 'a ht -> 'a list
but i don't know how to look in each bucket of a hashtable or to display the value of the bucket of the key. I would appreciate some help on what kind of an algorithm to use.
for example the function should work like this;
-lookup 3 (table [(1, [2,3]), (2, [3,4,5]), (3, [4])]);
val it = [4] : int list
-lookup 4 (table [(1, [2,3]), (2, [3,4,5]), (3, [4])]);
val it = [] : int list

Your hash table is a list of pairs.
for fun lookup n table = ...
First you will need a function to travel down the list of pairs to the nth position.
you could use something like
case table of
table [] => nil
|table ls => lookup n-1 table (tl ls)
Second get the value (#2 of the pair) or by pattern matching when the second argument of your lookup function is reduced to 1 in the recursion, assuming your keys are ranked in order like in your examples.
Then just return it.

Related

SML Create function receives list of tuples and return list with sum each pair

I'm studying Standard ML and one of the exercices I have to do is to write a function called opPairs that receives a list of tuples of type int, and returns a list with the sum of each pair.
Example:
input: opPairs [(1, 2), (3, 4)]
output: val it = [3, 7]
These were my attempts, which are not compiling:
ATTEMPT 1
type T0 = int * int;
fun opPairs ((h:TO)::t) = let val aux =(#1 h + #2 h) in
aux::(opPairs(t))
end;
The error message is:
Error: unbound type constructor: TO
Error: operator and operand don't agree [type mismatch]
operator domain: {1:'Y; 'Z}
operand: [E]
in expression:
(fn {1=1,...} => 1) h
ATTEMPT 2
fun opPairs2 l = map (fn x => #1 x + #2 x ) l;
The error message is: Error: unresolved flex record (need to know the names of ALL the fields
in this context)
type: {1:[+ ty], 2:[+ ty]; 'Z}
The first attempt has a typo: type T0 is defined, where 0 is zero, but then type TO is referenced in the pattern, where O is the letter O. This gets rid of the "operand and operator do not agree" error, but there is a further problem. The pattern ((h:T0)::t) does not match an empty list, so there is a "match nonexhaustive" warning with the corrected type identifier. This manifests as an exception when the function is used, because the code needs to match an empty list when it reaches the end of the input.
The second attempt needs to use a type for the tuples. This is because the tuple accessor #n needs to know the type of the tuple it accesses. To fix this problem, provide the type of the tuple argument to the anonymous function:
fun opPairs2 l = map (fn x:T0 => #1 x + #2 x) l;
But, really it is bad practice to use #1, #2, etc. to access tuple fields; use pattern matching instead. Here is a cleaner approach, more like the first attempt, but taking full advantage of pattern matching:
fun opPairs nil = nil
| opPairs ((a, b)::cs) = (a + b)::(opPairs cs);
Here, opPairs returns an empty list when the input is an empty list, otherwise pattern matching provides the field values a and b to be added and consed recursively onto the output. When the last tuple is reached, cs is the empty list, and opPairs cs is then also the empty list: the individual tuple sums are then consed onto this empty list to create the output list.
To extend on exnihilo's answer, once you have achieved familiarity with the type of solution that uses explicit recursion and pattern matching (opPairs ((a, b)::cs) = ...), you can begin to generalise the solution using list combinators:
val opPairs = map op+

Return a list of even numbers from a list of integer pairs in sml

I have the following question "Given a list of integer pairs, write a function to return a list of even numbers in that list in sml".
this is what I've achieved so far
val x = [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
fun isEven(num : int) =
if num mod 2 = 0 then num else 0;
fun evenNumbers(list : (int * int) list) =
if null list then [] else
if isEven(#1 (hd list)) <> 0
then if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
else []
else if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: evenNumbers(tl list)
else [];
evenNumbers(x);
the result should be like this [6,2,4,6,8,10]
any help would be appreciated.
I see two obvious problems.
If both the first and second number are even, you do
#1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
which adds the first number twice and ignores the second.
If the first number is odd and the second even, you do
#1 (hd list) :: evenNumbers(tl list)
which adds the number that you know is odd and ignores the one you know is even.
Programming with selectors and conditionals gets complicated very quickly (as you've noticed).
With pattern matching, you could write
fun evenNumbers [] = []
| evenNumber ((x,y)::xys) = ...
and reduce the risk of using the wrong selector.
However, this still makes for complicated logic, and there is a better way.
Consider the simpler problem of filtering the odd numbers out of a list of numbers, not pairs.
If you transform the input into such a list, you only need to solve that simpler problem (and there's a fair chance that you've already solved something very similar in a previous exercise).
Exercise: implement this transformation. Its type will be ('a * 'a) list -> 'a list.
Also, your isEven is more useful if it produces a truth value (if you ask someone, "is 36 even?", "36" is a very strange answer).
fun isEven x = x mod 2 = 0
Now, evenNumbers can be implemented as "just" a combination of other, more general, functions.
So running your current code,
- evenNumbers [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
val it = [6,6,3,5,7,9] : int list
suggests that you're not catching all even numbers, and that you're catching some odd numbers.
The function isEven sounds very much like you want to have the type int -> bool like so:
fun isEven n =
n mod 2 = 0
Instead of addressing the logic error of your current solution, I would like to propose a syntactically much simpler approach which is to use pattern matching and fewer explicit type annotations. One basis for such a solution could look like:
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) = ...
Using pattern matching is an alternative to if-then-else: the [] pattern is equivalent to if null list ... and the (x,y)::pairs pattern matches when the input list is non-empty (holds at least one element, being (x,y). At the same time, it deconstructs this one element into its parts, x and y. So in the second function body you can express isEven x and isEven y.
As there is a total of four combinations of whether x and y are even or not, this could easily end up with a similarly complicated nest of if-then-else's. For this I might do either one of two things:
Use case-of (and call evenNumbers recursively on pairs):
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) =
case (isEven x, isEven y) of
... => ...
| ... => ...
Flatten the list of pairs into a list of integers and filter it:
fun flatten [] = ...
| flatten ((x,y)::pairs) = ...
val evenNumbers pairs = ...

How do I map database columns to a struct in a list of structs in Racket?

I have a list called attendance-events, consisting of struct type attendance-event. The struct is defined as
(define-struct attendance-event (date flag))
The "date" is the date of the event and "flag" is a 2 character value that represents the type of event.
In my database, I am selecting "select date, code from attendance_table", and I want those two columns to be added to the list of attendance-events for each row.
So, how can this be done?
This performs the query and returns a list of attendance-event structures:
(for/list ([(date code)
(in-query conn "select date, code from attendance_table")])
(make-attendance-event date code))
I find it much easier to work with database rows after they've been converted to hash tables. The following function converts the rows-result type returned by the query function into a list of immutable hashes:
(require (planet jphelps/loop)) ;; Use the loop macro from Common Lisp.
(define (rows-result->hash results)
(let ((header (rows-result-headers results)))
(loop for row in (rows-result-rows results)
collect (loop for ((_ . name) (_ . decltype)) in header
for column across row
with-collection-type hash/immutable
collect (cons name column)))))
Then you can wrap the query function like this:
(define (simple-query query-text conn . params)
(rows-result->hash (apply query (list* conn query-text params))))
Finally, to create your struct:
(loop for row in (simple-query "select date,code from attendance_table;")
collect (make-attendance-event (hash-ref row 'date) (hash-ref row 'code)))

OCaml: Going from int list list to int

I am working on a OCaml motion detection program. It analyzes two images and detects if there was motion. One part requires me summing a row of values and then also summing an entire image. This is what I have currenly:
let rec sumImRow(maskedrow) =
match maskedrow with
| [] -> 0
| mskRhd::mskRtl -> mskRhd + (sumImRow mskRtl)
;;
let rec sumImage(maskedimage) =
match maskedimage with
| mskRhd::mskRtl -> (sumImRow mskRhd)::(sumImage mskRtl)
| _ -> []
;;
and the given value is int list list -> int list = <fun>.
I don't quite understand why this is giving me int list.
tl;dr: You construct a new list instead of summing the integers.
Well, we can agree that sumImRow has type int list -> int as it takes elements from the list and then return their sum.
sumImage will have a list argument as it deconstructs it in the pattern matching. It then returns the list of result of sumImRow, meaning sumImage gets as argument a list of what sumImRow takes and returns a list of results. So we indeed have int list list -> int list.
You can avoid that by replacing :: with + and [] with 0 in sumImage's matching result.
You can also make a more improved code by using List.fold_left:
let sumImRow l = List.fold_left (+) 0 l;;
let sumImage l = List.fold_left (List.fold_left (+)) 0 l;;
The two return values of sumImage are both lists. So naturally its return type is a list.
(Most likely you should be using + rather than :: in sumImage. And the base case should be 0 rather than [].)

Cant figure out what Error means and how to solve it

Here is the error code I have:
Characters 2004-2008
Error: The type constructor list expects 1 argument(s),
but is here applied to 0 argument(s)
Here is the Ocaml code I have written:
let createHuffmanTree (s:string) = match s with
| "" -> Empty (*Return an empty huffman tree ifstring is empty*)
| _ -> let rec ca (l: list) (a: huffman) = match l with (*ERROR SHOULD BE ON THIS LINE*)
| [] -> a (*If list is [] return the huffman tree*)
| x,_ -> fold_left (ca) l level(leaf(x),a) (*For all the ellement of the list create a level and corresponding leaf*)
in ca listFreq(explode(s)) Empty (*Start with an empty tree*)
Note:
explode take a string return it as a list of char
ex:
# explode "Test";;
- : char list = ['T'; 'e'; 's'; 't']
listFreq take the list from explode and return a pair of char * int being the char and the number of time it is found in the list return by explode
ex:
# listeFreq (explode "AABCAABADBACAAB");;
- : (char * int) list = [('A', 8); ('B', 4); ('C', 2); ('D', 1)]
The Huffman Tree I am trying to create take a string (for exemple "AAABBC")
and do this:
level
| |
v v
leaf A level
| |
v v
leaf B leaf C
The tree could also be Empty
Question:
I have no idea how to solve the error code. Could someone point out a solution?
I suppose that instead of (l: list), you should have something like (l: 'a list).

Resources