So I have this function
getSales :: (Num p, Eq t) => t -> [(t, p)] -> p
getSales day [] = 0
getSales day ((x,y):xs) | (day == x) = y + (getSales day xs) | otherwise = getSales day XS
So basically if I did getSales "Mon" storelog
and storelog was storelog = [("Mon",50),("Fri",20), ("Tue",20),("Fri",10),("Wed",25),("Fri",30)]
it would return 50. But now I want to be able to iterate through a tuple like this
sales = [("Amazon",[("Mon",30),("Wed",100),("Sat",200)]), ("Etsy",[("Mon",50),("Tue",20),("Wed",25),("Fri",30)]), ("Ebay",[("Tue",60),("Wed",100),("Thu",30)]), ("Etsy",[("Tue",100),("Thu",50),("Sat",20),("Tue",10)])]
With the company name given and then I use getSales to find the sales for the day asked.
sumSales:: (Num p)=> String -> String -> [(String,[(String,p)])] -> p
This is the function I have for the iteration for the company name given and such but I am having a real hard time understanding how to iterate through the tuple for it to find "Amazon" for example and then pass in the list of the sales for the days.
You've actually already implemented most of the logic needed in your getSales function - which I repeat below for reference, although tidying up the recursive case to put the guards on separate lines, this is much more readable and is how it would normally be written in practice:
getSales :: (Num p, Eq t) => t -> [(t, p)] -> p
getSales day [] = 0
getSales day ((x,y):xs)
| (day == x) = y + (getSales day xs)
| otherwise = getSales day XS
For your sumSales function, you just need to repeat this pattern. The only important differences are:
the function takes 2 arguments instead of 1
the second element of the tuples, denoted by y above, now isn't simply a number, but a list of tuples. So we can't simply add it to the result of the recursive call. However, what it is is a tuple consisting of a day name and a number, which is exactly the case you've already dealt with in getSales. So the solution is to make use of that function you've already written.
Taking account of the above, we get:
sumSales:: (Num p) => String -> String -> [(String, [(String, p)])] -> p
sumSales company day [] = 0
sumSales company day ((x, y) : xs)
| company == x = getSales day y + sumSales company day xs
| otherwise = sumSales company day xs
which will work as I believe you intend.
However, I don't particularly like these two functions. They are very "noisy", with a lot of details to process before you can understand what the functions do - and further, the important parts of the two functions are more or less the same. In particular, one common way in functional programming to write functions like these which "summarise" some information about a list is to use a "fold". So you could rewrite the functions in this way, which uses foldr to abstract away the common recursion pattern in both:
getSales day = foldr (\(x, y) sum -> if x == day then y + sum else sum) 0
sumSales company day = foldr (\(x, sales) sum -> if x == company then getSales day sales + sum else sum) 0
That is, in my opinion, better - but still not great. There's still repetition across the functions which we're using to fold in each case - both simply check a condition and use it to either add a new term or not.
The Haskell standard library - in fact, even the Prelude, the set of functions/types/classes available by default in every Haskell program, without any imports - already includes some functions for dealing with these things. In particular, there is sum for adding a list of numbers, filter for reducing a list to just those elements fulfilling a particular condition, and map for getting a new list from an old one by applying a function to each element. map, filter and the various folds are really the "bread and butter" of functional programming with lists, so I would advise becoming familiar and comfortable with them.
Using these common tools, we can write the two functions in much more readily understandable form:
getSales day = sum . map snd . filter (\(x, _) -> x == day)
sumSales company day = sum . map (getSales day . snd) . filter (\(x, _) -> x == company)
(One could argue I've taken these too far in terms of being "point free" - although I could have gone further and written eg \(x, _) -> x == day as (== day) . fst. The "best" way to write a function, in terms of readability, is very much a matter of opinion. I just wanted to show you that there are other ways to write these functions, and other similar ones you may need in future, that will likely make more sense to you when you come back to look at them later.)
Related
To start, let me share that I'm a complete novice at formal programming and have decided to start learning after many years of working in IT from the administrative side. So I am starting from scratch and hopefully unlearning any bad habits I've picked up over the years.
To help myself out, I've started a course online that has some homework. I've promised myself to not cheat, but I'm struggling on this problem and would like some help. I did see a similar post that was answered, but the answer doesn't make sense to me, so I'm asking again.
Here is the assignment ...
" Write a function "number_in_months" that takes a list of dates and a list of months (i.e., an int list) and returns the number of dates in the list of dates that are in any of the months in the list of months. Assume the list of months has no number repeated. Hint: Use your answer to the previous problem. "
You'll notice that it refers to the previous problem. I've shared it below.
" Write a function "number_in_month" that takes a list of dates and a month (i.e., an int) and returns how many dates in the list are in the given month. "
I was able to solve the previous problem with this code.
fun number_in_month (dates : (int * int * int) list , month : int ) =
if null dates
then 0
else
if ( #2 (hd dates) = month )
then 1 + number_in_month (tl dates , month)
else number_in_month (tl dates , month)
In my REPL val test2 = number_in_month ([(2012,2,28),(2013,12,1)],2) = 1 tests true
So I've re-read the material and re-watched the videos a few times and still haven't gotten to an understanding on how to solve the problem. I can get it all to type check correctly but then get an uncaught exception EMPTY
I can recurse the "dates" list against the hd of the "months" list with no problem but to move on to the next value in the "months" list is killing me. So far I have tried many ways, but I'm stumped, and I'm feeling not just a little stupid. ;-)
fun number_in_months (dates : (int * int * int) list , months : int list ) =
if null dates
then 0
else
if (#2 (hd dates) = (hd months))
then 1 + number_in_months ( tl dates , months )
else
????
It may be that I solved the first problem in such a way that it is throwing me off with the second. I'm open to any ideas, guidance, or clues. All will be appreciated
The more idiomatic way to handle empty lists and accessing elements of tuples in SML is pattern matching. If we consider your number_in_month function, we'd look at something like the following. If the list of dates is empty, it doesn't matter what month we're looking for, so we represent it with _.
Otherwise we consider the first tuple (but we only need to bind a name to the second element representing the month) and bind a name to the tail of the list. We count the tail of the list, and then if the current one is a match, add 1.
fun number_in_month([], _) = 0
| number_in_month(((_, mon, _)::other_dates), month) =
let
val count_remaining = number_in_month(other_dates, month)
in
(if mon = month then 1 else 0) + count_remaining
end;
For your numbers_in_months it seems you want to map over the list of months. List.map provides exactly this, and can directly use your prior work.
fun numbers_in_months(dates, months) =
List.map (fn m => number_in_month(dates, m)) months;
numbers_in_months([(2012, 2, 28), (2013, 12, 1)], [4, 12, 2]);
Returns:
[0, 1, 1]
map can be implemented trivially, even without the niceties of pattern-matching.
fun map f lst =
if null lst then []
else f (hd lst) :: map f (tl lst)
I need to change list for example:
[1,2,4,6,5,10]
To this one
[1,2,5] (the list of elements that are on correct position).
1st element value is 1 - ok,
element value is 2 - ok,
3rd element value is 4 but expected 3 (due to the index)- remove
and etc. How can I solve the error which is attached below?
My code:
module Count where
import Control.Monad.State
nthel n xs = last xsxs
where xsxs = take n xs
deleteNth i items = take i items ++ drop (1 + i) items
repeatNTimes 0 _ = return ()
repeatNTimes n xs =
do
if (n == nthel n xs) then return()
else deleteNth (n-1) xs
repeatNTimes (n-1) xs
list = [1,2,3,4,5]
main = repeatNTimes (length list) list
I have the following error:
* Couldn't match type `Int' with `()'
Expected type: [()]
Actual type: [Int]
* In the expression: deleteNth (n - 2) xs
In a stmt of a 'do' block:
if (n == nthel n xs) then return () else deleteNth (n - 2) xs
In the expression:
do { if (n == nthel n xs) then return () else deleteNth (n - 2) xs;
repeatNTimes (n - 1) xs }
A really nice way to work with this is to stitch functions together. First one might need to get to know the functions in the Data.List module, which you can find with hoogle: http://hoogle.haskell.org
Data.List Module functions
I'll give you a little bit of a boost here. The functions I would pick out are the zip function: https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-List.html#v:zip whose type is [a] -> [b] -> [(a, b)] and then the filter function https://hackage.haskell.org/package/base-4.9.1.0/docs/Prelude.html#v:filter whose type is (a -> Bool) -> [a] -> [a] and then the map function whose type is (a -> b) -> [a] -> [b] along with the fst :: (a, b) -> a
Function Composition
These functions can be stitched together using the function composition operator: (.) :: (b -> c) -> (a -> b) -> a -> c it takes two functions that share a common input/output point (in the type signature they are the second and first parameters, respectively; a -> b and b -> c) and it will then join them into one single function.
Stacking it up - required knowledge
In order to do what you want to do, you really need to know about simple types, parameterised types, ranges (including lazy infinite ranges would help), functions and possibly recursion as well some higher order functions and how Haskell functions are curried, and to understand function composition. It wouldn't hurt to add a basic understanding of what typeclasses do and are into the mix.
I helped author a tutorial which can really help with understanding how this stuff works from a usage point of view by following a series of interesting examples. It's not too long, and you might find it much easier to approach your problem once you have understood some of the more foundational stuff: http://happylearnhaskelltutorial.com — note that it's not tuned to teaching you how to construct stuff, that'll be coming in a later volume, but it should give you enough understanding to be able to at least guess at an answer, or understand the one below.
The Answer - spoilers
If you want to work this out yourself, you should stop here and come back later on when you're feeling more confident. However, I'm going to put one possible answer just below, so don't look if you don't want to know yet!
positionals :: (Enum a, Eq a, Num a) => [a] -> [a]
positionals = map fst . filter (\(x, y) -> x == y) . zip [1..]
Keep in mind this is only one way of doing this. There are simpler more explanatory ways to do it, and while it might possibly seem inefficient, Haskell has list/stream fusion which compiles that function into something that will do a single pass across your data.
Update: What I want to do with this code is to get a list of dates, year/month/day and a given number as a month, and check to see how many of the dates in the given list are in the same month as that given month. What I meant of x = x + 1 was x++ such as in java or C or C#. As the output I want x. if there is no match, 0 and for any match x = x + 1
So this is my code,
fun number_in_month (Dlist : (int * int * int) list, Month : int, x : int) =
if null Dlist then x
else if #2 (hd Dlist) = Month then x = x + 1 andalso number_in_month (tl(Dlist), Month, x)
else number_in_month ((tl(Dlist)), Month, x)
and it gives me error:
Error: types of if branches do not agree [tycon mismatch]
then branch: int
else branch: bool
in expression:
if null Dlist
then x
else if (fn <rule>) (hd <exp>) = Month
then (x = <exp> + <exp>)
andalso (number_in_month (<exp>,<exp>,<exp>))
else number_in_month (tl <exp>,Month,x)
I really don't get it why sml is considering x = x + 1 of type bool. I'd be really happy if someone could tell me how can I correctly say x = x + 1 in sml.
Thanks a lot in advance.
Saying x = x + 1 in Standard ML, you need to clarify what you intend to say, because clearly x = x + 1 means something you don't intend. What it means is "Compare x with x + 1 and say if they are equal" (which they never will be of any integer).
What I suppose you want to achieve is "update x to its successor", which is not possible without the use of reference types, which I discourage since they are not immutable and functional. The way you usually update something functionally is by passing an updated value to a function that eventually returns it. (Using function arguments as accumulating variables, so it feels as if it's the same variables that update their value e.g. upon each recursive call.)
Another thing I recommend that you do is use pattern matching instead of if-then-else. For example, you know that the list is empty if it matches []. Since the result of your computation is not a boolean, you cannot use "... andalso ..." -- I suspect you do this because you "want to do two things at once, and andalso smells like "doing something and also doing something else", but this would be a misconception. You can do this (using e.g. ; or before), but you would lose your result because these operators deal with side-effects and discard the main effect of one of their operands, so it is not what you want at this point.
Here is my stab in the dark at what you intended, written using pattern matching:
fun number_in_month ([], _, x) = x
| number_in_month ((one,two,three)::dlist, month, x) =
if two = month then number_in_month(dlist, month, x+1)
else number_in_month(dlist, month, x)
Modified: You can also do this without tail-recursion
fun number_in_month([], _) = 0
| number_in_month((_,month1,_)::dlist, month2) =
if month1 = month2 then 1 + number_in_month(dlist, month2)
else number_in_month(dlist, month2)
Or written differently:
fun number_in_month([], _) = 0
| number_in_month((_,month1,_)::dlist, month2) =
(if month1 = month2 then 1 else 0) + number_in_month(dlist, month2)
Or using list combinators:
fun counter(n1,n2) = if n1 = n2 then 1 else 0
fun number_in_month(dlist, month2) =
foldl (fn ((_,month1,_),count) => counter(month1,month2) + count) 0 dlist
Or using reference, as you asked for, even though I discourage this:
fun number_in_month (dlist, month2) =
let val count = ref 0
fun loop [] = !count (* the value inside the ref-cell *)
| loop ((_,month1,_)::dlist) =
if month1 = month2 then (count := !count + 1 ; loop dlist)
else loop dlist
in loop dlist end
As you can see, some complexity is added because I wish to create the ref-cell within the function, but I cannot create a new ref-cell upon every recursive call. So I create a helper function that is recursive and let it have the argument that changes during recursion (it can just inherit month2 and count from the parent scope of number_in_month. When recursion ends (base case), I choose to return the value within the ref-cell (using Standard ML's slightly obscure syntax for dereferencing).
Don't make it a habit of using ref-cells before you master the functional way. Otherwise you are back to coding imperatively in a language that makes this habit ugly. :)
Scenario:
If there is an array of integers and I want to get array of integers in return that their total should not exceed 10.
I am a beginner in Haskell and tried below. If any one could correct me, would be greatly appreciated.
numbers :: [Int]
numbers = [1,2,3,4,5,6,7,8,9,10, 11, 12]
getUpTo :: [Int] -> Int -> [Int]
getUpTo (x:xs) max =
if max <= 10
then
max = max + x
getUpTo xs max
else
x
Input
getUpTo numbers 0
Output Expected
[1,2,3,4]
BEWARE: This is not a solution to the knapsack problem :)
A very fast solution I came up with is the following one. Of course solving the full knapsack problem would be harder, but if you only need a quick solution this should work:
import Data.List (sort)
getUpTo :: Int -> [Int] -> [Int]
getUpTo max xs = go (sort xs) 0 []
where
go [] sum acc = acc
go (x:xs) sum acc
| x + sum <= max = go xs (x + sum) (x:acc)
| otherwise = acc
By sorting out the array before everything else, I can take items from the top one after another, until the maximum is exceeded; the list built up to that point is then returned.
edit: as a side note, I swapped the order of the first two arguments because this way should be more useful for partial applications.
For educational purposes (and since I felt like explaining something :-), here's a different version, which uses more standard functions. As written it is slower, because it computes a number of sums, and doesn't keep a running total. On the other hand, I think it expresses quite well how to break the problem down.
getUpTo :: [Int] -> [Int]
getUpTo = last . filter (\xs -> sum xs <= 10) . Data.List.inits
I've written the solution as a 'pipeline' of functions; if you apply getUpTo to a list of numbers, Data.List.inits gets applied to the list first, then filter (\xs -> sum xs <= 10) gets applied to the result, and finally last gets applied to the result of that.
So, let's see what each of those three functions do. First off, Data.List.inits returns the initial segments of a list, in increasing order of length. For example, Data.List.inits [2,3,4,5,6] returns [[],[2],[2,3],[2,3,4],[2,3,4,5],[2,3,4,5,6]]. As you can see, this is a list of lists of integers.
Next up, filter (\xs -> sum xs <= 10) goes through these lists of integer in order, keeping them if their sum is less than 10, and discarding them otherwise. The first argument of filter is a predicate which given a list xs returns True if the sum of xs is less than 10. This may be a bit confusing at first, so an example with a simpler predicate is in order, I think. filter even [1,2,3,4,5,6,7] returns [2,4,6] because that are the even values in the original list. In the earlier example, the lists [], [2], [2,3], and [2,3,4] all have a sum less than 10, but [2,3,4,5] and [2,3,4,5,6] don't, so the result of filter (\xs -> sum xs <= 10) . Data.List.inits applied to [2,3,4,5,6] is [[],[2],[2,3],[2,3,4]], again a list of lists of integers.
The last step is the easiest: we just return the last element of the list of lists of integers. This is in principle unsafe, because what should the last element of an empty list be? In our case, we are good to go, since inits always returns the empty list [] first, which has sum 0, which is less than ten - so there's always at least one element in the list of lists we're taking the last element of. We apply last to a list which contains the initial segments of the original list which sum to less than 10, ordered by length. In other words: we return the longest initial segment which sums to less than 10 - which is what you wanted!
If there are negative numbers in your numbers list, this way of doing things can return something you don't expect: getUpTo [10,4,-5,20] returns [10,4,-5] because that is the longest initial segment of [10,4,-5,20] which sums to under 10; even though [10,4] is above 10. If this is not the behaviour you want, and expect [10], then you must replace filter by takeWhile - that essentially stops the filtering as soon as the first element for which the predicate returns False is encountered. E.g. takeWhile [2,4,1,3,6,8,5,7] evaluates to [2,4]. So in our case, using takeWhile stops the moment the sum goes over 10, not trying longer segments.
By writing getUpTo as a composition of functions, it becomes easy to change parts of your algorithm: if you want the longest initial segment that sums exactly to 10, you can use last . filter (\xs -> sum xs == 10) . Data.List.inits. Or if you want to look at the tail segments instead, use head . filter (\xs -> sum xs <= 10) . Data.List.tails; or to take all the possible sublists into account (i.e. an inefficient knapsack solution!): last . filter (\xs -> sum xs <= 10) . Data.List.sortBy (\xs ys -> length xscomparelength ys) . Control.Monad.filterM (const [False,True]) - but I'm not going to explain that here, I've been rambling long enough!
There is an answer with a fast version; however, I thought it might also be instructive to see the minimal change necessary to your code to make it work the way you expect.
numbers :: [Int]
numbers = [1,2,3,4,5,6,7,8,9,10, 11, 12]
getUpTo :: [Int] -> Int -> [Int]
getUpTo (x:xs) max =
if max < 10 -- (<), not (<=)
then
-- return a list that still contains x;
-- can't reassign to max, but can send a
-- different value on to the next
-- iteration of getUpTo
x : getUpTo xs (max + x)
else
[] -- don't want to return any more values here
I am fairly new to Haskell. I just started with it a few hours ago and as such I see in every question a challenge that helps me get out of the imperative way of thinking and a opportunity to practice my recursion thinking :)
I gave some thought to the question and I came up with this, perhaps, naive solution:
upToBound :: (Integral a) => [a] -> a -> [a]
upToBound (x:xs) bound =
let
summation _ [] = []
summation n (m:ms)
| n + m <= bound = m:summation (n + m) ms
| otherwise = []
in
summation 0 (x:xs)
I know there is already a better answer, I just did it for the fun of it.
I have the impression that I changed the signature of the original invocation, because I thought it was pointless to provide an initial zero to the outer function invocation, since I can only assume it can only be zero at first. As such, in my implementation I hid the seed from the caller and provided, instead, the maximum bound, which is more likely to change.
upToBound [1,2,3,4,5,6,7,8,9,0] 10
Which outputs: [1,2,3,4]
I'm very new with Haskell, only starting to learn it.
I'm using "Learn You a Haskell for Great Good!" tutorial for start, and saw example of solving "3n+1" problem:
chain :: (Integral a) => a -> [a]
chain 1 = [1]
chain n
| even n = n:chain (n `div` 2)
| odd n = n:chain (n*3 + 1)
numLongChains :: Int
numLongChains = length (filter isLong (map chain [1..100]))
where isLong xs = length xs > 15
so, numLongChains counts all chains that longer 15 steps, for all numbers from 1 to 100.
Now, I wanna my own:
numLongChains' :: [Int]
numLongChains' = filter isLong (map chain [1..100])
where isLong xs = length xs > 15
so now, I wanna not to count these chains, but return filtered list with these chains.
But now I get error when compiling:
Couldn't match expected type `Int' with actual type `[a0]'
Expected type: Int -> Bool
Actual type: [a0] -> Bool
In the first argument of `filter', namely `isLong'
In the expression: filter isLong (map chain [1 .. 100])
What can be the problem?
The type signature of numLongChains is probably not correct. Depending on what you want to do, one of the following is needed:
You simply want to count those chains, your function numLongChains obviously shall return a number, change the first line to length $ filter isLong (map chain [1..100]) and the type to Int
You want to return a list of lengths of the long chains. In this case, the type signature is fine, but you need to return a length. I'd suggest you, the calculate the length before filtering and filter on it. The function's body becomes filter (>15) (map (length . chain) [1..100]).
You want to return all chains that are longer than 15 chars. Just change the signature to [[Int]] (A list of chains (lists) of Ints) and you're fine.
FUZxxl is right. You are going to want to change the type signature of your function to [[Int]]. As you are filtering a list of lists and only selecting the ones that are sufficiently long, you will have returned a lists of lists.
One note about reading Haskell compile-time debugger/errors. This error may seem strange. It says you had [a0] -> Bool but you were expecting Int -> Bool. This is because that the type checker assumes that, from the signature of your numLongChains' function, you are going to need a filter function that checks Ints and returns a list of acceptable ones. The only way to filter over a list and get [Int] back is to have a function that takes Ints and returns Bools (Int -> Bool). Instead, it sees a function that checks length. Length takes a list, so it guesses that you wrote a function that checks lists. ([a0] -> Bool). Sometimes, the checker is not as friendly as you would like it to be but if you look hard enough, you will see that 9 times out of 10, a hard to decipher error is the result of such as assumptions.