Adding to list and incrementing - Haskell - haskell

import Data.Char
-- Sample test data
testData :: [Movies]
testData = [("Me and My Broken Heart","Rixton"),
("It’s My Birthday","will.i.am"),
("Problem","Ariana Grande")]
-- record a sale of a track
record :: [Movies] -> String -> String
record t a = []
record ((t, a): xs) a a
| t == a && a == a = [(t,a)]
| otherwise = record xs a t
The correct output should be a modified version of the database.

First, since it seems you're learning, a few notes on style: in a case like this, it is a convention to name one sale with a singular form, and the list of them with the plural, that is:
type Sale = (String, String, Int)
type Sales = [Sale]
Even better, one would often (depending on intended usage and taste) turn Sale into a newtype or full ADT, since that gives you more abstraction and type safety.
Second, to your actual question: the behavior you're seeing comes from the order of pattern matching. In your first match,
recordSale testData aTitle anArtist = []
testDate matches any list, also non-empty ones, before the second pattern can apply. Change that to
recordSale [] _ _ = []
and you won't get only empty lists anymore. Additionally, as #Aleksandar notes, you should not forget to keep the init of the list in cases where the list is not empty, but the filter criteria don't match.

Haskell is a functional language, and encapsulates stateful modifications to data very well in the type system. The usual way of "mutating" a value in Haskell would be to either use a stateful computation (in the ST or State Monad) or to just use recursion and duplicate the values. I think you should learn the latter first.
The function you used will return [] in case aTitle and anArtist don't match any of the entries in the list. Otherwise it will return a list with one single element in it, namely the newly modified one.
You need to build up the list incrementally as you traverse it. Remember, you're basically copying it:
-- record a sale of a track
recordSale :: [Sales] -> String -> String -> [Sales]
recordSale [] aTitle anArtist = []
recordSale ((title, artist, qty): xs) aTitle anArtist
| title == aTitle && artist == anArtist =
(title, artist, qty+1):recordSale xs aTitle anArtist
| otherwise = (title,artist,qty):recordSale xs aTitle anArtist
This should give you the right results. Notice what's different here: you have a recursive call to the function in both cases, and in both cases, too, you're appending the current element either modified or unmodified to the list you're building.
You should also think about your data structure. Having tuples with comments is not a very nice way of constructing complex data structures. Try
data Record = Record { title :: String, artist :: String, quantity :: Integer }
You could even make a couple of newtypes like newtype Title = Title String. Remember, creating data types in Haskell is cheap, and you should be doing it constantly.

Related

Matching Int to dataType for Bool

I want to create a data type that's either New [Int] or Empty; then I want to use an Int and check if the data type contains the Int. This is probably an extremely simple question but I'm new to creating data types and using them in functions, specifically getting a handle on the syntax; I don't have a grounded understanding of it yet.
data New = New [Int]
| Empty
deriving Show
check :: Int -> New -> Bool
check x ys
| x `elem` New ys = True
| otherwise = False
You'll want check to pattern-match on its New argument to access the underlying list, if any.
check :: Int -> New -> Bool
check x Empty = False
check x (New ys) = x `elem` ys
One way to collapse the definition a bit is to realize that as far as check is concerned, the values Empty and New [] are equivalent.
check :: Int -> New -> Bool
check x ys = x `elem` (case ys of
New ys' -> ys'
Empty -> [])
Even though this is an exercise in using custom data types, I feel like expanding on chepner's question, "What does Empty provide that New [] does not?" since it was not met with any response: Lists can already be empty, so you could make your check without a custom data type definition:
check :: Int -> [Int] -> Bool
check = elem
With the type that Robin said was isomorphic to your New type, Maybe, it would look like:
type New = Maybe [Int]
check :: Int -> New -> Bool
check _ Nothing = False
check x (Just xs) = x `elem` xs
Generally when the standard library offers a data type isomorphic to your current one, you should ask yourself if you want to create your own one. Sometimes it is warranted, but often you will want to use either type or newtype and not data.
With this type, Maybe [Int], you must ask yourself why you want to differentiate between Nothing and Just []. For example, Nothing could indicate that the function failed, while Just [] could indicate that it succeeded, but that the (correct) result was empty.
An example of a function where this makes sense is the Change exercise on Exercism:
Correctly determine the fewest number of coins to be given to a customer such that the sum of the coins' value would equal the correct amount of change.
Here Nothing means that it's not possible to give exact change, and Just [] means that the customer paid the exact amount and needs no change.
If, instead, you'd like some exercises that deal with writing functions for custom data types, see the "W3" exercises on https://github.com/opqdonut/haskell-exercises.

case-of / case expression with or in pattern matching possible?

I am learning haskell on my own. And was working on implementing a custom List data type using basic lists and case of.
So data structure is something similar to this
data List = List [String] | EmptyList deriving Show
now if I am doing case expressions for base case, I have to do two matchings. A simple example would be the size function
size :: List -> Int
size lst = case lst of
(List []) -> 0
EmptyList -> 0
(List (x:xs)) -> 1 + size (List xs)
Can't I do something like combining the two base cases of list being empty (List []) and EmptyList somehow to reduce redundancy?
size :: List -> Int
size lst = case lst of
(List []) | EmptyList -> 0
(List (x:xs)) -> 1 + size (List xs)
I have tried searching all over the net for this, but unfortunately wasn't able to find anything concrete over matching multiple patterns in one case.
First of all you should consider why you have separate constructors for List and EmptyList in the first place. The empty list clearly is already a special case of a list anyway, so this is an awkward redundancy. If anything, you should make it
import Data.List.NonEmpty
data List' a = NEList (NonEmpty a) | EmptyList
Another option that would work for this specific example is to make the empty case into a “catch-all pattern”:
size :: List -> Int
size lst = case lst of
(List (x:xs)) -> 1 + size (List xs)
_ -> 0
BTW there's no reason to use case here, you can also just write two function clauses:
size :: List -> Int
size (List (x:xs)) = 1 + size (List xs)
size _ = 0
Anyways – this is generally discouraged, because catch-all clauses are an easy place for hard to detect bugs to creep in if you extend your data type in the future.
Also possible, but even worse style is to use a boolean guard match – this can easily use lookups in a list of options, like
size lst | lst`elem`[EmptyList, List []] = 0
size (List (x:xs)) = 1 + size (List xs)
Equality checks should be avoided if possible; they introduce an Eq constraint which, quite needlessly, will require the elements to be equality-comparable. And often equality check is also more computationally expensive than a pattern match.
Another option if you can't change the data structure itself but would like to work with it as if List [] and EmptyList were the same thing would be to write custom pattern synonyms. This is a relatively recent feature of Haskell; it kind of pretends the data structure is actually different – like List' – from how it's really layed out.
In the comments, you say
there are no such functions [which should return different results for EmptyList and List []]
therefore I recommend merging these two constructors in the type itself:
data List = List [String] deriving Show
Now you no longer need to distinguish between EmptyList and List [] in functions that consume a List.
...in point of fact, I would go even further and elide the definition entirely, simply using [String] everywhere instead. There is one exception to this: if you need to define an instance for a class that differs in behavior from [String]'s existing instance. In that exceptional case, defining a new type is sensible; but I would use newtype instead of data, for the usual efficiency and semantics reasons.

Filtering for values in Haskell

I've been doing some Haskell exercises from a Haskell book, and one of the tasks is for me to filter for values of a certain type and return them as a list.
import Data.Time
data Item = DbString String
| DbNumber Integer
| DbDate UTCTime
deriving (Eq, Ord, Show)
database :: [Item]
database =
[
DbDate (UTCTime (fromGregorian 1911 5 1) (secondsToDiffTime 34123)),
DbNumber 9001,
DbString "Hello World!",
DbDate (UTCTime (fromGregorian 1921 5 1) (secondsToDiffTime 34123))
]
That's the code I am given to work with, and for my first task:
Write a function that filters for DbDate values and returns a list of the UTCTime values inside them. The template for the function is:
filterDate :: [Item] -> [UTCTime]
filterDate = undefined
What I have to use here are folds since that is the matter concerned here.
I looked up the Data.Time module on Hoogle and that didn't really help since I couldn't understand how to interact with the module. Maybe I'm looking at this from a wrong perspective because I don't think it has something to do with the filter function, and I don't think it has something to do with type-casting neither ::.
How do I get UTCTime values, and how do I filter for them?
OK, my Haskell-fu is extremely weak but I'm going to have a stab at an answer. You're looking to define a function that walks across a list and filters it. If the value is a DbDate then you return <that value> : <output list>, otherwise you return <output list>. By folding over the input you produce a filtered output. There's a relevant question at How would you define map and filter using foldr in Haskell? which might explain this better.
This breaks down to something like:
filterFn :: Item -> [UTCTime] -> [UTCTime]
filterFn (DbDate x) xs = x:xs
filterFn _ xs = xs
(this might be a syntax fail). This function takes an item off our [Item] and pattern matches.
If it matches DbDate x then x is a UTCTime and we append it to our input list.
If it doesn't then we ignore it and return the input list unchanged.
We can then fold:
filterDate = foldr filterFn []
Does that get you to an answer?
Item is defined as a union type, which means it can be a DbString, a DbNumber or a DbDate.
data Item = DbString String
| DbNumber Integer
| DbDate UTCTime
deriving (Eq, Ord, Show)
You can use pattern matching to get only the value you're interested in. You need to match on an item, check whether it is a DbDate and if that's the case extract the UTCTime instance it holds.
You said you want to use a fold so you need an accumulator where you can put the values you want to keep and a function to populate it.
filterDate items = foldl accumulate [] items
where extractTime item = case item of DbDate time -> [time]
_ -> []
accumulate item accumulator = accumulator ++ (extractTime item)
In the code above you have extractTime that pattern matches over an item and either returns a list containing the time or it returns an empty list. The accumulate function just puts together the values you got from the previous steps (they're stored in accumulator) and the value you got applying extractTime to the current item.

Outputting the contents of a list of a custom data type

I have a custom data type Movie = String Int [(String,Int)] (Movie Name Year [(Fan,Rating)] and want to do a couple of things:
First I want to make a function that averages the Ints from the list of tuples and just outputs that number. So far I have this incomplete function:
avgRating :: [DataType] -> Int
avgRating [(Movie a b [(fan,rating)])] = sumRatings / (length [<mylist>])
Here I need a function sumRatings to recurse through the list and sum all the ratings, but i'm not sure where to start.
The other issue I have here is that i'm not sure what to put where <mylist> is as I would normally give the list a variable name and then use it there, but since I have split the list up to define other variables I can't name it.
I hope that makes sense, thanks.
I'm guessing you have a data structure defined as
data Movie = Movie String Int [(String, Int)]
While this works, it can be a bit cumbersome to work with when you have that many fields. Instead, you can leverage type aliases and record syntax as
type Name = String
type Year = Int
type Rating = Int
data Movie = Movie
{ mName :: Name
, mYear :: Year
, mRatings :: [(Name, Rating)]
} deriving (Eq, Show)
Now things are a bit more explicit and easier to work with. The mName, mYear, and mRatings functions will take a Movie and return the corresponding field from it. Your Movie constructor still works in the same way too, so it won't break existing code.
To calculate the average of the ratings, you really want a function that extracts all the ratings for a movie and aggregates them into a list:
ratings :: Movie -> [Rating]
ratings mov = map snd $ mRatings mov
Then you just need an average function. This will be a bit different because you can't calculate the average of Ints directly, you'll have to convert to a floating point type:
average :: [Rating] -> Float -- Double precision isn't really needed here
average rs = fromIntegral (sum rs) / fromIntegral (length rs)
The fromIntegral function converts an Int to a Float (the actual type signature is a bit more general). Since both the sum of Ints is an Int and the length of a list is always an Int, you need to convert both.
Now you can just compose these into a single function:
movieAvgRating :: Movie -> Float
movieAvgRating = average . ratings
Now, if you need to calculate the average ratings for several movies, you can apply ratings to each of them, aggregate them into a single list of ratings, then call average on that. I would suggest looking at the concatMap function. You'll be wanting to make a function like
moviesAvgRating :: [Movie] -> Float
moviesAvgRating movs = average $ ???
To answer your second question first, you can bind to a variable and unpack it simultaneously using #:
avgRating [(Movie a b mylist#[(fan, rating)])] = …
Note also that if you’re not going to be using variables that you unpack, it’s Haskell convention to bind them to _:
avgRating [(Movie _ _ mylist#[(fan, rating)])] = …
This helps readers focus on what’s actually important.
I don’t want to just give you the solution to your recursion problem, because learning to write recursive functions is an important and rewarding part of Haskell programming. (If you really want me to spoil it for you, let me know in a comment.) The basic idea, however, is that you need to think about two different cases: a base case (where the recursion stops) and a recursive case. As an example, consider the built-in sum function:
sum :: Num a => [a] -> a
sum [] = 0
sum (x:xs) = x + sum xs
Here, the base case is when sum gets an empty list – it simply evaluates to 0. In the recursive case, we assume that sum can already produce the sum of a smaller list, and we extend it to cover a larger list.
If you’re having trouble with recursion in general, Harold Abelson and Gerald Jay Sussman present a detailed discussion on the topic in Structure and Interpretation of Computer Programs, 2nd ed., The MIT Press (Cambridge), 1996, starting on p. 21 (§§1.1.7–1.2). It’s in Scheme, not Haskell, but the languages are sufficiently similar – at least at this conceptual level – that each can serve as a decent model for the other.

Does there exist something like (xs:x)

I'm new to Haskell. I know I can create a reverse function by doing this:
reverse :: [a] -> [a]
reverse [] = []
reverse (x:xs) = (Main.reverse xs) ++ [x]
Is there such a thing as (xs:x) (a list concatenated with an element, i.e. x is the last element in the list) so that I put the last list element at the front of the list?
rotate :: [a] -> [a]
rotate [] = []
rotate (xs:x) = [x] ++ xs
I get these errors when I try to compile a program containing this function:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `rotate'
I'm also new to Haskell, so my answer is not authoritative. Anyway, I would do it using last and init:
Prelude> last [1..10] : init [1..10]
[10,1,2,3,4,5,6,7,8,9]
or
Prelude> [ last [1..10] ] ++ init [1..10]
[10,1,2,3,4,5,6,7,8,9]
The short answer is: this is not possible with pattern matching, you have to use a function.
The long answer is: it's not in standard Haskell, but it is if you are willing to use an extension called View Patterns, and also if you have no problem with your pattern matching eventually taking longer than constant time.
The reason is that pattern matching is based on how the structure is constructed in the first place. A list is an abstract type, which have the following structure:
data List a = Empty | Cons a (List a)
deriving (Show) -- this is just so you can print the List
When you declare a type like that you generate three objects: a type constructor List, and two data constructors: Empty and Cons. The type constructor takes types and turns them into other types, i.e., List takes a type a and creates another type List a. The data constructor works like a function that returns something of type List a. In this case you have:
Empty :: List a
representing an empty list and
Cons :: a -> List a -> List a
which takes a value of type a and a list and appends the value to the head of the list, returning another list. So you can build your lists like this:
empty = Empty -- similar to []
list1 = Cons 1 Empty -- similar to 1:[] = [1]
list2 = Cons 2 list1 -- similar to 2:(1:[]) = 2:[1] = [2,1]
This is more or less how lists work, but in the place of Empty you have [] and in the place of Cons you have (:). When you type something like [1,2,3] this is just syntactic sugar for 1:2:3:[] or Cons 1 (Cons 2 (Cons 3 Empty)).
When you do pattern matching, you are "de-constructing" the type. Having knowledge of how the type is structured allows you to uniquely disassemble it. Consider the function:
head :: List a -> a
head (Empty) = error " the empty list have no head"
head (Cons x xs) = x
What happens on the type matching is that the data constructor is matched to some structure you give. If it matches Empty, than you have an empty list. If if matches Const x xs then x must have type a and must be the head of the list and xs must have type List a and be the tail of the list, cause that's the type of the data constructor:
Cons :: a -> List a -> List a
If Cons x xs is of type List a than x must be a and xs must be List a. The same is true for (x:xs). If you look to the type of (:) in GHCi:
> :t (:)
(:) :: a -> [a] -> [a]
So, if (x:xs) is of type [a], x must be a and xs must be [a] . The error message you get when you try to do (xs:x) and then treat xs like a list, is exactly because of this. By your use of (:) the compiler infers that xs have type a, and by your use of
++, it infers that xs must be [a]. Then it freaks out cause there's no finite type a for which a = [a] - this is what he's trying to tell you with that error message.
If you need to disassemble the structure in other ways that don't match the way the data constructor builds the structure, than you have to write your own function. There are two functions in the standard library that do what you want: last returns the last element of a list, and init returns all-but-the-last elements of the list.
But note that pattern matching happens in constant time. To find out the head and the tail of a list, it doesn't matter how long the list is, you just have to look to the outermost data constructor. Finding the last element is O(N): you have to dig until you find the innermost Cons or the innermost (:), and this requires you to "peel" the structure N times, where N is the size of the list.
If you frequently have to look for the last element in long lists, you might consider if using a list is a good idea after all. You can go after Data.Sequence (constant time access to first and last elements), Data.Map (log(N) time access to any element if you know its key), Data.Array (constant time access to an element if you know its index), Data.Vector or other data structures that match your needs better than lists.
Ok. That was the short answer (:P). The long one you'll have to lookup a bit by yourself, but here's an intro.
You can have this working with a syntax very close to pattern matching by using view patterns. View Patterns are an extension that you can use by having this as the first line of your code:
{-# Language ViewPatterns #-}
The instructions of how to use it are here: http://hackage.haskell.org/trac/ghc/wiki/ViewPatterns
With view patterns you could do something like:
view :: [a] -> (a, [a])
view xs = (last xs, init xs)
someFunction :: [a] -> ...
someFunction (view -> (x,xs)) = ...
than x and xs will be bound to the last and the init of the list you provide to someFunction. Syntactically it feels like pattern matching, but it is really just applying last and init to the given list.
If you're willing to use something different from plain lists, you could have a look at the Seq type in the containers package, as documented here. This has O(1) cons (element at the front) and snoc (element at the back), and allows pattern matching the element from the front and the back, through use of Views.
"Is there such a thing as (xs:x) (a list concatenated with an element, i.e. x is the last element in the list) so that I put the last list element at the front of the list?"
No, not in the sense that you mean. These "patterns" on the left-hand side of a function definition are a reflection of how a data structure is defined by the programmer and stored in memory. Haskell's built-in list implementation is a singly-linked list, ordered from the beginning - so the pattern available for function definitions reflects exactly that, exposing the very first element plus the rest of the list (or alternatively, the empty list).
For a list constructed in this way, the last element is not immediately available as one of the stored components of the list's top-most node. So instead of that value being present in pattern on the left-hand side of the function definition, it's calculated by the function body onthe right-hand side.
Of course, you can define new data structures, so if you want a new list that makes the last element available through pattern-matching, you could build that. But there's be some cost: Maybe you'd just be storing the list backwards, so that it's now the first element which is not available by pattern matching, and requires computation. Maybe you're storing both the first and last value in the structures, which would require additional storage space and bookkeeping.
It's perfectly reasonable to think about multiple implementations of a single data structure concept - to look forward a little bit, this is one use of Haskell's class/instance definitions.
Reversing as you suggested might be much less efficient. Last is not O(1) operation, but is O(N) and that mean that rotating as you suggested becomes O(N^2) alghorhim.
Source:
http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/src/GHC-List.html#last
Your first version has O(n) complexity. Well it is not, becuase ++ is also O(N) operation
you should do this like
rotate l = rev l []
where
rev [] a = a
rev (x:xs) a = rev xs (x:a)
source : http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/src/GHC-List.html#reverse
In your latter example, x is in fact a list. [x] becomes a list of lists, e.g. [[1,2], [3,4]].
(++) wants a list of the same type on both sides. When you are using it, you're doing [[a]] ++ [a] which is why the compiler is complaining. According to your code a would be the same type as [a], which is impossible.
In (x:xs), x is the first item of the list (the head) and xs is everything but the head, i.e., the tail. The names are irrelevant here, you might as well call them (head:tail).
If you really want to take the last item of the input list and put that in the front of the result list, you could do something like:
rotate :: [a] -> [a]
rotate [] = []
rotate lst = (last lst):(rotate $ init lst)
N.B. I haven't tested this code at all as I don't have a Haskell environment available at the moment.

Resources