Calculate Price of items in a list - list

I am learning algebraic-data-types in Haskell, and I ran into a problem I cannot solve.
So I want to enter a list of groceries, and as an output I should get the total price.
For now, I have the types:
data Item = A | B | C deriving (Eq, Show)
data List = Empty | Add Item List
and I have the groceries list: list1 = A `Add` (B `Add` Empty)
I have a function (That sets the prices of the items):
p:: Item -> Int
p A = 2
p B = 4
p C = 5
And now here is where I have a difficulty.
I want to apply the function "p" to my list1. But I am not sure how.
Here is my current code:
price:: (Item -> Int) -> List -> Int
price p (Add x xs)
| x == A = A + price xs
| x == B = B + price xs
| x == C = C + price xs
| otherwise = 0
I also tried this.
price:: (Item -> Int) -> List -> Int
price p (Add x xs) = x + price xs
Thanks in advance!

price's first parameter is a function which accepts List parameter and returns Int (like the declared p function, but do not confuse it with p parameter in price p (Add x xs) pattern, I renamed the former one for clarity to c), so the implementation can look like the following:
price :: (Item -> Int) -> List -> Int
price _ Empty = 0 -- match empty List
price c (Add x xs) = (c x) + price c xs -- match non-empty and perform recursive call to price
With call looking like price p $ Add A Empty (calculates price of list of one A).

In addition to chepner's suggestion to implement mapList I might suggest writing foldrList.
foldrList _ i Empty = i
foldrList f i (Add x xs) = f x (foldrList f i xs)
Having done so, the total price of a list of items can be calculated:
totalPrice items = foldrList (\item acc -> p item + acc) 0 items
Or simply:
totalPrice = foldrList (\item acc -> p item + acc) 0

Related

How to compute the average of a list of a special record in OCaml?

Lets say we have a record which defines students:
type student = {
name : string;
age : int;
grades : (float) list;
}
And safe them in a list like this:
let studentlist = [ {name="alex"; age=7; grades=[1.;2.;3.]} ;
{name="bianca"; age=6; grades=[1.;1.;2.]} ];;
My aim is to compute the grade average of a special student which I choose per age, I select the student with the function search:
let search a lst = List.find( fun {age;_} -> a = age)lst
And compute the average with the help-functions , named sum, length and finally avr :
let rec sum lst =
match lst with
| [] -> 0.0
| h :: t -> h +. sum t
let length lst = float_of_int (List.length lst);;
let avr lst = sum lst /. length lst;;
I don't know how to combine those functions to compute the average properly!
Most of what you've done seems to work. For instance, search works.
utop # search 7 studentlist;;
- : student = {name = "alex"; age = 7; grades = [1.; 2.; 3.]}
If you want to access the grades field of that record, use . for record access.
utop # (search 7 studentlist).grades;;
- : float list = [1.; 2.; 3.]
Now that you have a list of float values, finding the sum or average of them should be easy by passing that value as an argument to the relevant function you've already defined.
Bear in mind that when you use List.find in search, if you search for an age that is not present, you will get a Not_found exception that you will want to handle.
As an aside, note that your avr function iterates over the list twice. Once to compute the sum, and ocne to compute the length.
It is possible to computer the sum, the length, and the average in a single pass. We can use a fold to do this. First off, we can define a basic left fold:
let rec foldl f init lst =
match lst with
| [] -> init
| x::xs -> foldl f (f init x) xs
Consider using this to compute the length of a list:
foldl (fun i _ -> i + 1) 0 [1.; 2.; 3.]
When evaluated:
foldl (fun i _ -> i + 1) 0 [1.; 2.; 3.]
foldl (fun i _ -> i + 1) (0 + 1) [2.; 3.]
foldl (fun i _ -> i + 1) (1 + 1) [3.]
foldl (fun i _ -> i + 1) (2 + 1) []
3
But we can pass a tuple of values to foldl, building up the length, sum, and average as we go.
utop # let (len, sum, avg) = foldl
(fun (len, sum, avg) x ->
let sum = sum +. x in
let len = len + 1 in
let flen = float_of_int len in
(len, sum, sum /. flen))
(0, 0., 0.)
[1.; 2.; 3.];;
val len : int = 3
val sum : float = 6.
val avg : float = 2.

How to use fold on an elaborate function in ocaml

As the title suggests, I want to use fold. If I understand correctly, it it used to apply a function to every item in a list. That's what I want to do with my function, but I don't know how to format it.
Here is the function I want to use with fold :
let pairing list =
let rec aux counter length paired list = match list with
| [] -> paired
| [head] -> paired
| head :: head' :: tail -> if counter = length then aux (counter-1) length ((head, head) :: paired) (head :: head' :: tail) else aux counter length ((head, head') :: paired) (head' :: tail)
in List.rev(aux (List.length(listheads list)) (List.length(listheads list)) [] (listheads list));;
What it does is it returns a list of all the items in the list paired together.
For example, if my list is [3;4;2], it should return
[(3,3); (3,4); (3,2); (4,3); (4,4); (4,2); (2,3); (2,4); (2,2)]
What it returns at the moment is only [(3,3); (3,4); (3,2)], because the function only applies to the first item of the list.
Here are all the helper functions :
let rec member list x = match list with
| [] -> false
| head :: tail -> head = x || member tail x
let head_list list =
let rec aux l1 list = match list with
| [] -> l1
| (x,y) :: tail -> aux (x :: l1) tail
in List.rev (aux [] list);;
let head'_list list =
let rec aux l2 list = match list with
| [] -> l2
| (x,y) :: tail -> aux (y :: l2) tail
in List.rev (aux [] list);;
let listheads list =
let rec aux returnlist l1 l2 = match l1 with
| [] -> returnlist
| head :: tail -> if member l2 head = true && member returnlist head = false then aux (head :: returnlist) tail l2 else aux returnlist tail l2
in List.rev(aux [] (head_list list) (head'_list list));;
What listheads does is it will take my original list (say [(3,4); (4,2); (2,3); (4,7); (9,4)]), use head_list and head'_list in order to determine which integers are both in head and head' position in the tuple, and put them in the list (in the case I gave, [3;4;2]).
I know that fold takes a function, an empty list and a list as arguments, but I don't know how to use pairing with fold.
Your code need to make a double pass on the list
let pairing l =
let second_pass x acc y = ...... in
let first_pass acc el = ....... in
List.fold_left first_pass [] l |> List.rev
The first pass function should call the second pass function, and the second pass function will create the pair element. Free to you for completing the code of the two functions.
Here the result I have :
utop # pairing [3 ; 4 ; 2];;
- : (int * int) list =
[(3, 3); (3, 4); (3, 2); (4, 3); (4, 4); (4, 2); (2, 3); (2, 4); (2, 2)]
It's very difficult to answer your question because there's no clean place to add a fold to get the result you want.
It might be more fruitful just to debug your code. It seems to me you're using your counter backwards. Its initial value is the length of the list and it is decremented for each recursive call. But your test for termination tests against the length of the list. It seems to me you should be testing against 0 (or possibly 1).
If you have a function f that does something interesting to a value, and you have a list of the values, you can use List.map to get a list of the values of f applied to each element of the list. You don't need a fold for that.
The purpose of a fold is to compute thing other than just a list of the function values. For examle, if each call to f makes a list of values, you could use a fold to keep concatenating these lists into a longer list.
Let's say f makes a value x into a list [x; x]. Then you can create a (reversed) doubled list something like this:
let f x = [x; x]
let double l =
let aux sofar x = f x # sofar in
List.fold_left aux [] l
# double [1;2;3];;
- : int list = [3; 3; 2; 2; 1; 1]
You could possibly follow this pattern if you can come up with a function like f that transforms a value into a list. If you define f inside your outer function it will have access to the initial list.

How can write two statement within then statement?

I am writing a code in Haskell which take a list of 0's and 1's like [1,1,0,0,1,0,1] return a Pair(tuple) of the number occurrence of 0 and 1 in a list like (3,4).
Here is my code:
inc :: Int -> Int
inc x = (\x -> x + 1) x
count :: [Int] -> (Int,Int)
c = (0,0)
count x =
if null x
then c
else if head x == 0
then do
inc (fst c)
count (tail x)
else if head x == 1
then do
inc (snd c)
count (tail x)
I have also tried doing it in a guarded form:
count :: [Int] -> (Int,Int)
c = (0,0)
count x
| null x = c
| head x == 0 = inc (fst c) >> count (tail x)
| head x == 1 = inc (snd c) >> count (tail x)
The main problem is that I am not sure how to implement two function in one then statement.
You're thinking all imperatively. Something like do { inc (fst c); count (tail x) } would only make sense if c was some kind of mutable state variable. Haskell variables are not mutable, so inc can't modify the fst of c, it can only give you a modified copy. This might become clearer if you rewrite inc to the completely equivalent simpler form:
inc x = x + 1
(In fact, inc = (+1) would also do.)
Now, in count, you're trying to carry on and increment a single accumulator variable through the recursion loop. You can do that, but you need to be explicit about passing the modified version to the recursive call:
count = go (0,0)
where go :: (Int,Int) -> [Int] -> (Int,Int)
go c x
| null x = c
| head x == 0 = go (first inc c) (tail x)
| head x == 1 = go (second inc c) (tail x)
This pattern of defining a small local helper function (go is just an arbitrary name, I could have also called it getTheCountingDone) and using it as the “loop body” of the recursion is quite common in Haskell. Basically go (0,0) “initialises” c to the value (0,0), then starts the first loop iteration. For the second iteration, you recurse to e.g. go (first inc c), i.e. you start the loop again with the updated c variable.
I've used first and second for incrementing the respective tuple field. fst only reads the first field, i.e. gives you its value, whereas first makes a tuple-update function from an element-update function. Instead of import Control.Arrow you could also define this yourself:
first :: (a->b) -> (a,y) -> (b,y)
first f (a, y) = (f a, y)
second :: (a->b) -> (x,a) -> (x,b)
second f (x, a) = (x, f a)
(The Control.Arrow version is actually more general, but you don't need to worry about that – you can use it in just the same way.)
Note that deconstructing lists with head and tail is heavily eschewed in Haskell: it's easy to get wrong – you may forget to check the list is nonempty before accessing an element, which will throw a nasty runtime error. Better use pattern matching:
count = go (0,0)
where go c [] = c
go c (0:xs) = go (first inc c) xs
go c (1:xs) = go (second inc c) xs
Actually this is still not safe: you don't have exhaustive cases; the function fails if the list contains anything but zeroes or ones. Perhaps you'd like to count all zero and nonzero elements?
count = go (0,0)
where go c [] = c
go c (0:xs) = go (first inc c) xs
go c (_:xs) = go (second inc c) xs
another alternative
> import Data.List(group,sort)
> count = tuplify . map length . group . sort
where tuplify [x,y] = (x,y)
One solution would be to filter the list twice, once keeping the zeroes, and once keeping the ones:
count :: [Int] -> (Int, Int)
count nums = (length (filter (0 ==) nums), length (filter (1 ==) nums))
One option would be to have a second parameter for your count function which keeps track of what you have already counted:
count :: [Int] -> (Int, Int) -> (Int, Int)
-- if the list is empty, return the ones and zeroes already counted
count [] (zeroes, ones) = (zeroes, ones)
-- if first element is a 0, increment the existing count for zeroes
-- and count the rest
count (0:more) (zeroes, ones) = count more (zeroes + 1, ones)
-- as before, but the first element is a 1
count (1:more) (zeroes, ones) = count more (zeroes, ones + 1)
When we call count, we have to give it a 'starting count' of (0,0):
count [1,0,1,1,1,0,0,1] (0,0)
which returns (3,5) as the first 0 in the initial pair is incremented 3 times by the zeroes in the list, and the second 0 in the initial pair is incremented 5 times by the ones in the list.
This solution is a common functional programming style called 'accumulating parameter'.

How many elements are the same in two lists (haskell)

I try to learn how many elements are the same in the given two sets. To be clear,
let a = ["t","k","m"]
let b = ["k","b","t","c"]
"t" and "k" are parts of both lists, so the return will be 2. How can I implement like this function without using any library and using recursion?
You can use the module Data.Set to convert the two lists to sets and calculate the size of the intersection:
let a = Set.fromList ["t","k","m"]
let b = Set.fromList ["k","b","t","c"]
print $ Set.size (a `Set.intersection` b)
Live demo
As a general rule, if the order of the elements in the list doesn't matter and the list doesn't contain duplicates it's a good idea to convert it into a Set.
For some reason you don't want to use the standard library. If you don't care about algorithmic complexity you can then use:
length $ Prelude.filter (`elem` b) a
Live demo
of if you want it to be put into recursive form, then it's something like this:
countDuplicates :: (Eq a) => [a] -> [a] -> Int
countDuplicates [] b = 0
countDuplicates (x:rest) b =
let index = if x `elem` b then 1 else 0
in index + countDuplicates rest b
Live demo
which if you don't want to use elem either will be further expanded to:
countDuplicates :: (Eq a) => [a] -> [a] -> Int
countDuplicates [] b = 0
countDuplicates (x:rest) b =
let myElem a [] = False
myElem a (al:lst) = if a == al then True else myElem a lst
index = if x `myElem` b then 1 else 0
in index + countDuplicates rest b
Live demo
Without using any extra functions you can write it simply as follows
countIntersect :: (Eq a) => [a] -> [a] -> Int
countIntersect _ [] = 0
countIntersect [] _ = 0
countIntersect (x:xs) y'#(y:ys) | x==y = 1 + countIntersect xs ys
| otherwise = countIntersect [x] ys + countIntersect xs y'
essentially, the way you would do by hand, compare the first two elements if same increase the counter and move the next element in both list. If not equal compare the first element of the first list with the rest of second list and remainder of the first list to the second list.

OCaml recursive function int list -> int -> (int list * int list)

Studying for a midterm and was looking through some old exam questions. This one doesn't have a solution posted and is stumping me:
partition: int list -> int -> (int list * int list) divides its
first argument into two lists, one containing all elements less than
its second argument, and the other all the elements greater than or
equal to its second argument. partition [5;2;10;4] 4 = ([2],
[5;10;4])
oh, and i'm supposed to be able to find the solution without using an auxiliary function
here is as far as i've gotten:
let rec partition l n = match l with
| [] -> ([], []) (* must return this type *)
| x :: xs -> if x < n then (* append x to first list, continue recursing *)
else (* append x to second list, continue recursing *)
normally, I'd use an aux function with an extra parameter to store the pair of lists i'm building, but that can't be done here. i'm a bit stuck
You should use the let in construction to match the return value of the recursive call:
let rec partition l n = match l with
| [] -> ([], [])
| x :: xs -> let a, b = partition xs n in
if x < n then (x::a), b
else a, (x::b);;