Find a datatype in list by comparing first value in haskell - haskell

I have a list of data types and I want to find the one that matches the first value, if it exists. If it does not exist, I want to return a default value.
data MyType = MyType String Int
findOrMake :: [MyType] -> String -> Int
findOrMake list x = do i <- -- find index
-- if i is a value, return the x[i]
-- if i is not a value, return (MyType x 0)
I have an intuition that I should use fmap and find, but I have never used either before.

How about a simple recursive solution?
data MyType = MyType String Int
findOrMake :: [MyType] -> String -> Int
findOrMake [] s = 42
findOrMake ((MyType mstr mint):ms) s = if mstr == s then mint else findOrMake ms s

To provide a default when the item is not found, you can use fromMaybe:
fromMaybe :: a -> Maybe a -> a
Combined with find, it should look something like this:
fromMaybe defaultValue $ find predicate list

Related

Using data constructor as a function parameter

I am making my way through "Haskell Programming..." and, in Chapter 10, have been working with a toy database. The database is defined as:
data DatabaseItem = DBString String
| DBNumber Integer
| DBDate UTCTime
deriving (Eq, Ord, Show)
and, given a database of the form [databaseItem], I am asked to write a function
dbNumberFilter :: [DatabaseItem] -> [Integer]
that takes a list of DatabaseItems, filters them for DBNumbers, and returns a list the of Integer values stored in them.
I solved that with:
dbNumberFilter db = foldr selectDBNumber [] db
where
selectDBNumber (DBNumber a) b = a : b
selectDBNumber _ b = b
Obviously, I can write an almost identical to extract Strings or UTCTTimes, but I am wondering if there is a way to create a generic filter that can extract a list of Integers, Strings, by passing the filter a chosen data constructor. Something like:
dbGenericFilter :: (a -> DataBaseItem) -> [DatabaseItem] -> [a]
dbGenericFilter DBICon db = foldr selectDBDate [] db
where
selectDBDate (DBICon a) b = a : b
selectDBDate _ b = b
where by passing DBString, DBNumber, or DBDate in the DBICon parameter, will return a list of Strings, Integers, or UTCTimes respectively.
I can't get the above, or any variation of it that I can think of, to work. But is there a way of achieving this effect?
You can't write a function so generic that it just takes a constructor as its first argument and then does what you want. Pattern matches are not first class in Haskell - you can't pass them around as arguments. But there are things you could do to write this more simply.
One approach that isn't really any more generic, but is certainly shorter, is to make use of the fact that a failed pattern match in a list comprehension skips the item:
dbNumberFilter db = [n | DBNumber n <- db]
If you prefer to write something generic, such that dbNUmberFilter = genericFilter x for some x, you can extract the concept of "try to match a DBNumber" into a function:
import Data.Maybe (mapMaybe)
genericFilter :: (DatabaseItem -> Maybe a) -> [DatabaseItem] -> [a]
genericFilter = mapMaybe
dbNumberFilter = genericFilter getNumber
where getNumber (DBNumber n) = Just n
getNumber _ = Nothing
Another somewhat relevant generic thing you could do would be to define the catamorphism for your type, which is a way of abstracting all possible pattern matches for your type into a single function:
dbCata :: (String -> a)
-> (Integer -> a)
-> (UTCTime -> a)
-> DatabaseItem -> a
dbCata s i t (DBString x) = s x
dbCata s i t (DBNumber x) = i x
dbCata s i t (DBDate x) = t x
Then you can write dbNumberFilter with three function arguments instead of a pattern match:
dbNumberFilter :: [DatabaseItem] -> [Integer]
dbNumberFilter = (>>= dbCata mempty pure mempty)

Haskell lookup table to return functions

Trying to extend "The Maybe monad" example on this page. Their lookup table phonebook:
phonebook :: [(String, String)]
phonebook = [ ("Bob", "01788 665242"),
("Fred", "01624 556442"),
("Alice", "01889 985333"),
("Jane", "01732 187565") ]
and there chained monad examples:
getRegistrationNumber :: String -- their name
-> Maybe String -- their registration number
getRegistrationNumber name =
lookup name phonebook >>=
(\number -> lookup number governmentalDatabase)
What happens if we want to return a function (that then returns a specific type) instead? So extending from their example, instead of looking up a registration number, we want to lookup lookup either their age, their ZIP, or the years that there property taxes were paid. Given these examples, an INT seems appropriate for the first two, and a List of Ints for the last. FIRST Question: since the lookup table has a type, must all of the return types of the functions be of the same type? I am assuming yes, but am unsure, hence the next question.
lets say that we write these 'finding' functions that return the same type [Int]. Maybe something like these:
getAge :: String -> Maybe [Int]
getAge phoneNumberString =
lookup name phonebook >>==
(\phoneNumberString -> lookup phoneNumberString governmentalAgeDatabase)
getZip :: String -> Maybe [Int]
getZip phoneNumberString =
lookup name phonebook >>==
(\phoneNumberString -> lookup phoneNumberString governmentalZipCodeDatabase)
getTaxPaidYears :: String -> Maybe [Int]
getTaxPaidYears phoneNumberString =
lookup name phonebook >>==
(\phoneNumberString -> lookup phoneNumberString governmentalTaxYearDatabase)
Now, assuming each of the the *Databases return an [Int] type, Second Question How do we write ONE function like lookupPersonsInformation that would return the appropriate information from what's typed in the input String, and given a lookup that returns the appropriate function, returns the information requested? Here is what I am trying to make work:
lookupAppropriateFunction :: [(String, String -> [Int])] --Here I want the second part
-- of the tuple to be the functions
lookupAppropriateFunction = [ ("age", getAge),
("zip", getZip),
("taxes", getTaxPaidYears) ]
lookupPersonsInformation :: String -> Maybe [Int]
lookupPersonsInformation nameAndInfo =
lookup ( words nameAndInfo!!0 ) >>=
( \phoneNumberString -> lookup ( words nameAndInfo!!1 ) lookupAppropriateFunction )
-- >> lookupPersonsInformation "Bob age"
[53] --Bob's age
-- >> lookupPersonsInformation "Fred zip"
[28202] --Fred's age
-- >> lookupPersonsInformation "Alice taxes"
[2010,2011,2013] --Alice's paid taxes years, It looks like she skipped 2012 :)
It is apparent that the errors propagate through to the end as Nothing, but I am unsure how to take the next step in applying this to a higher order function. Is it more in the parsing using words or in the structure of the lookup table that I want to return a function`
I ended up with going with something like the following:
-------------------------------------------------------------------------
intPusher :: String -> Stack -> Maybe Stack
-- ^ Takes a word, and tries to turn it into an Int, and push it onto the stack
intPusher word = case (reads word) of
[] -> \stak -> Nothing
[(x,"")] -> \stak -> Just (x:stak)
[(x,y)] -> \stak -> Nothing
-------------------------------------------------------------------------
dicLookup :: String -> Stack -> Maybe Stack
-- ^ Takes a word, and looks it up in the dictionary
dicLookup word = case (lookup word wordsTable) of
Nothing -> intPusher word
Just f -> f
-------------------------------------------------------------------------
wordsTable :: [(String, Stack -> Maybe Stack)]
-- ^ Checks the string against the commands
wordsTable = [ ("+", addIt)
,("-", subIt)
,("*", multIt)
,("/", divIt)
,("/MOD", modQuotIt)
,("MOD", modIt)
....
,("2DROP", drop2It) ]
-------------------------------------------------------------------------
interpretProgram :: String -> Maybe Stack
interpretProgram str = foldl (>>=) (Just[]) (map dicLookup (words str))
and for each tuple value in the dictionary, I provided the function declaration:
-------------------------------------------------------------------------
addIt :: Stack -> Maybe Stack
-- ^ Adds the first two elements of the stack
addIt stak = case stak of
x:y:xs -> Just (x + y:xs)
x:xs -> Nothing
_ -> Nothing
-------------------------------------------------------------------------
subIt :: Stack -> Maybe Stack
-- ^ Subtracts the first two elements of the stack
subIt stak = case stak of
x:y:xs -> Just (y - x:xs)
x:xs -> Nothing
_ -> Nothing
-------------------------------------------------------------------------
multIt :: Stack -> Maybe Stack
-- ^ Multiplies the first two elements of the stack
multIt stak = case stak of
x:y:xs -> Just (x * y:xs)
x:xs -> Nothing
_ -> Nothing
...
This works by taking a string, breaking it into individual 'words' (if possible, and returning Nothing if it can't) that are then passed into a dictionary to lookup the value of the word compared to the keys in the dictionary, thus acting like a lookup table. If the word is a key in the dictionary, it returns the value, which is a higher order function that does certain tasks (just like the words function, if the higher order function encounters an error, it will return Nothing).
When dealing with Monads, there are only TWO types of return values. Maybe AnyType and Nothing. An AnyType can be any type already declared in the module, or any basic type in Haskell (Int, Char, [Char], etc...). The trick is to return either a Maybe AnyType or a Nothing type. Since Haskell requires terminal declaration for if statements, it can be convention to 'catch' any potential errors and pass along the 'Nothing' type to the final return of a [grand]parent function.

Haskell function that returns arbitrary number of fields as list

I want to write a Haskell function that takes a custom type with eleven fields and returns either a list of all the fields' values, or a map associating the fields' names with their values. I don't want to have to explicitly get every field because that would be verbose and less versatile. Is there any way to do this?
What you write would be possible to some degree, but it wouldn't be very useful.
Let's imagine we insist on writing this function for a moment. Given that the fields' values may have different types, you probably rather want to yield a tuple. I.e.
data MyType = MyType Int String Bool
getFields :: MyType -> (Int, String, Bool)
getFields (MyType a b c) = (a,b,c)
So you could now call it like
let v = MyType 1 "Hello" True
let (x, y, z) = getFields v
Now, this isn't actually very useful, because you could use pattern matching in all of these cases, e.g.
let v = MyType 1 "Hello" True
let (MyType x y z) = v
Alright, but what if you wanted to address individual fields? Like
let x = fst (getFields v)
...how to do that without a 'getFields' function? Well, you can simply assign field names (as you probably already did):
data MyType = MyType
{ i :: Int
, s :: String
, b :: Bool
}
Now you could functions for accessing indivial fields for free:
let x = i v
...since assigning names ot fields actually generates functions like i :: MyType -> Int or s :: MyType -> String.

How do I pattern match on different types?

data Test = [Int] | Int
foobar :: Test -> Int
What if I wanted something like foobar [1,2,3] = 1 and foobar 1 = 1. In erlang it would be
foobar(X) when is_list(X) -> hd(X);
foobar(X) -> X.
First of all, your data-declaration is invalid. In Haskell, you have to start a data-declaration with a data-constructor, that is later matched upon. For instance, your type Test would be written
data Test = TLst [Int] | TInt Int
Now you can simply match on the type-constructor; it's field is a list or an int, depending on which constructor you match:
foobar :: Test -> Int
foobar (TLst (x:xs)) = x
foobar (TLst []) = error "empty list passed to foobar"
foobar (TInt x) = x
The other approach to this is to use a typeclass, like so:
class Test a where
foobar a -> Int
instance Test Int where
foobar x = x
instance Test [Int] where
foobar [] = error "Empty list"
foobar (x:_) = x
The pattern matching is implicit here--the type passed to foobar determines which instance we choose.
But you probably don't want to be doing this sort of thing unless there's a symmetry in your problem that makes it sensible to think of Int and [Int] as two examples of the same sort of thing. The better your types match the problem you're solving, the more the typechecker can help you.
Firstly, this is not valid Haskell syntax:
data Test = [Int] | Int -- this doesn't work
The alternatives require their own constructors. So this is valid:
data Test = TestA [Int] | TestB Int
Then you can pattern match like this:
foobar :: Test -> Int
foobar (TestA listOfInt) = length listOfInt
foobar (TestB int) = int

Haskell data type pattern matching

Lets say you have
data SS=
SSliteral Value
and
data Value=
SSint Int
Now lets say you have n which is of type SS. You want to get the Int value of SS, how would you go about doing so?
You pattern match on n.
getIt :: SS -> Int
getIt (SSliteral (SSint x)) = x
I suggest you read lyah.
We define with record syntax:
data SS = SSliteral {
ssValue :: Value
}
data Value = SSint {
ssInt :: Int
}
now we define
getIt :: SS -> Int
getIt = ssInt . ssValue
And now we are point-free.

Resources