I need to create a phonebook as a list of tuples:
type Phonebook :: [(String,String)]
As you can see in the code, the first element should represent the name and the second element the number. So the result of
Main> phonebookone = insert "Dad" "90213" (insert "mum" "8912" emptyPhonebook)
Main> phonebookone
should be [("Dad","90213"),("mum","8912")] but I only get [("Dad","90213")]
My code:
emptyPhonebook :: Phonebook
emptyPhonebook = [("","")]
insert :: String -> String -> Phonebook -> Phonebook
insert name number phonebook = [(name,number)]
Also i need to create a function search, which search for numbers or better if the first element of a tuple exists in the list and is the same like the String, who you search for, it will result the second element of the tuple.
So it should be:
Main> search "Dad" phonebook
"90213"
My unfinished code for this:
search :: String -> Phonebook -> String
search name phonebook = if ..???
A lot of things are wrong with your code:
Your emptyPhonebook actually is not empty: indeed you have defined one tuple in it: the one with an empty string as both the name and the phone number. You can correct this to:
emptyPhonebook :: Phonebook
emptyPhonebook = []
Your insertion method insert actually creates a Phonebook with one entry: the one you want to add, the remainder of the phonebook is ignored. You can use the CONS ((:)) function for this:
insert :: String -> String -> Phonebook -> Phonebook
insert name number = (:) (name,number)
Now to answer the main question. First of all, most Haskell programmers consider if to be rather un-Haskell: in Haskell one uses pattern matching and guards to set constraints on rules.
Since your search is probably supposed to error when it does not find a person with that name (you did not specify this), there are actually two code paths we have to consider:
the one where we are given a non-empty list where the first element matches our search: in that case we return the corresponding number; and
the one where the name does not match in which case we simply continue our search in th tail of the given list.
These rules in Haskell look like:
search query ((name,number):other) = ...
Now in case query and name match, we thus should return the number so:
search query ((name,number):other) | query == name = number
In the other case, we recursively continue our noble quest:
search query ((name,number):other) | otherwise = search query other
So putting it together, you get:
search :: String -> Phonebook -> String
search query ((name,number):other) | query == name = number
| otherwise = search query other
This will return the number given it is in the phonebook, and otherwise error.
EDIT:
Given you want to return "error" (as a string) when the search fails, you only have to add an additional rule:
search _ [] = "error"
So putting it all together gives:
search :: String -> Phonebook -> String
search query ((name,number):other) | query == name = number
| otherwise = search query other
search _ [] = "error"
As already mentioned your insert function is incomplete, otherwise no matter what you try to insert to it it'll only have 1 record, so if you try to search for a specific contact in your phonebook it'll only retrieve the only 1. But I won't answer that as that has already been answered.
Then just apply simple recursion over your phonebook
search :: String -> Phonebook -> String
search name ((contactName, contactNumber):phonebook) = if contactName == name then contactNumber else search name phonebook
or you can use filter
search :: String -> Phonebook -> String
search name phonebook = snd . head . filter ((==name) . fst) $ phonebook
The only problem with the second option that it will retrieve the first contact with the same name and it might not be the one we're querying for, a solution to this would be to use Either String phonebook as the return type if there is more than one individual with the same name, so this:
search :: String -> Phonebook -> Either String phonebook
search name phonebook = let getContacts nm contacts = filter ((==nm) . fst) $ contacts
in case (length $ getContacts name phonebook) == 1 of
True -> Left $ snd . head . getContacts name $ phonebook
False -> Right $ (getContacts name) $ phonebook
Ignore the last one, is untested and I don't think is exactly what you want, I just added this just in case as extra.
Related
I have a database table that I have tried to model in OCaml. However, I get problems when I try to write a function that extracts columns. I have managed to write a function that takes a table with only one column, but if I have a table with more columns then I get a match failure. I would need help with how to denotate my table in my pattern matching.
(* Table with many columns *)
let tableWithManyColumns =
"carTable",
[ ("RegNumber", ["1";"2";"3";"4"]);
("Brand", ["BMW";"SAAB";"Volvo";"Jeep"]);
("Year",["2000";"2003";"2001";"2012"]);
];;
(*Table with one columns*)
let tableWithOneColumn = "carTable",
[
("RegNumber", ["1";"2";"3";"4"])
];;
(*Current extractColumn*)
let extractColumn (t:string * (string * string list) list) =
match t with
(a,[(b,c)])-> b;;
(* Returns Regnumber *)
extractColumn(tableWithOneColumn);;
(*Returns match failure*)
extractColumn(tableWithManyColumns);;
The pattern [(b,c)] matches with a singleton list of pairs. So it will match with [("hello", "world)] but will not match with [("hello", "world"); ("another", "pair")], or [] or any list which length is not equal to one. If you want to match with any list with length more than one, you need to use the first :: rest pattern, where first will match with the first element of the list, and rest with the rest part of the list (everything beyond the first element).
The following function will extract the name of the first column,
type column = string * string list (* name, values *)
type base = string * column list (* tableName, columns *)
let firstColumnName : base -> string = fun table -> match table with
| (_tableName, (columnName,_values) :: _otherColumns) -> columnName
| _ -> failwith "wrong table representation"
Example,
# firstColumnName tableWithOneColumn;;
- : string = "RegNumber"
# firstColumnName tableWithManyColumns;;
- : string = "RegNumber"
Say that I have a self made dictionary made from a list of tuples
let menu = [("pizza",17);("hotdog",5);("burger", 12);("drink",3);("milkshake",4)]
I want to write a search function that takes both my dictionary and a key value as a parameter, then returns an option type with the value if key can be found in dict, and None if it can't.
I feel like this is a problem built around f# recursion, using and returning option types as well as obtaining individual values from a tuple, but I'm having a hell of a time putting them together and getting anything that comes even remotely close to accomplishing this task.
I've come up with some pseudo-code that I believe would solve the problem, but actual f# implementation is another story. In an imperative language this seems like a trivial problem, but trying to grasp functional has been really difficult.
//create function `search` accepts dictionary and search key
//match searchkey with dictionary key
//if searchkey = dictionary key, return option type w/ value
//if searchkey <> dictionary key, recurse call next dict values
//if end of dictionary, doesn't exist, return none
//Here's a *very* rough sketch of what I think should be happening.
let rec search dict key =
match dict with
//first check for an empty list, if empty return None
| [] -> None
//next check that there is a head and a tail for dict
//also check for match between first element of head and key
//if match, return hd
//still needs to return option type though, but how?
| hd :: tl when fst hd = key -> snd hd
//finally call search on the tail
| _ :: tl -> search tl key
The empty list condition and the wildcard pattern I'm fairly sure are correct, but it's the actual check and return that im stuck on. How might I go about that particular step?
Patterns can be nested inside other patterns. The tuple pattern (a, b) can be nested inside the list head/tail pattern head :: tail like this: (a, b) :: tail
This means the second pattern match can look like this (k, v) :: _ when k = key.
You need to return an option from every branch, so either a Some x or a None. The second match branch was missing a Some wrapper.
The code with both changes:
let rec search dict key =
match dict with
| [] -> None
| (k, v) :: _ when k = key -> Some v
| _ :: tl -> search tl key
They way to think about recursion, is to just get one example right. And leave the remaining list to the recursive function. And you must somehow accomplish that the "remaining" list gets smaller.
First, you deal with a list. One way to think about it is to just check one element at a time. So you extract the first element of a list, do something with it, then repeat the recursive function on the remaining list. So you could start with:
let search key lst =
match lst with
| head :: tail ->
Think of your example list, in this case. The first invocation of your example list your head would be ("pizza",17).
The next step you now need to-do is. Deconstruct the tuple into key and value and check them. You deconstruct it with
let (k, v) = head
Then you need to check if your k is equal to key. If it is equal, then you want to return the value.
if k = key
then Some v
The else branch must handle the case where your k is not the key you search. This is the recursive step. You want to repeat the checking on the remaining list items.
else search key tail
Remember at this point tail is now your menu with the first element removed. Currently you have the following code.
let rec search key lst =
match lst with
| head :: tail ->
let (k, v) = head
if k = key
then Some v
else search key tail
But this code does not handle the case when it cannot find your item. Think what would happen if the if k = key is never true! It will remove one-element at a time, then recursive on the remaining list until you end up with the empty list.
Empty list then means, you didn't find the key. To be successful you now need to add a case for the empty list. In that case your key is not in your list, and you must return "None". So you end up with:
let rec search key lst =
match lst with
| [] -> None
| head :: tail ->
let (k, v) = head
if k = key
then Some v
else search key tail
I am learning Haskell and I have a problem where if given a list of a list of a list of Strings I have to find the total number of Strings in the entire initial list. My though process was to convert the entire initial list into a one dimensional list and get the length, however I can seem to figure it out.
What I have so far:
type Word = String
type Line = [Word]
type Page = [Line]
type Doc = [Page]
numWords :: Doc -> Line -> Word -> Int
I need to find the number of Words and I'm not sure if this is even the best way to go about this type of problem, but I am at a loss for ideas.
Any help would be much appreciated.
Thank you.
This is quite a simple problem.
If we have a look at the types, it becomes easy:
type Word = String
type Line = [String]
type Page = [[String]]
type Doc = [[[String]]]
It's not too difficult to get the length of a Line:
lenLine x = length x
The Page is just the sum of all the inner lengths:
lenPage xs = sum $ map lenLine xs
And we can use the same kind of pattern for Doc:
lenDoc xs = sum $ map lenPage xs
As for your final function , just use all the others:
numWords :: Doc -> Page -> Line -> Int
numWords dc pg ln = lenDoc dc + lenPage pg + lenLine ln
Remember that a type synonym doesn't mean that the type is actually different; you can use the same functions.
I have the following tuples:
type Id = Int
type Name = String
type FSK = Int
type Movie = (Id, Name, FSK)
now I want to define a function that extracts a movie from a given list like that:
extract :: Id -> [Movie] -> (Maybe Movie, [Movie])
extract = .... ??
so that when I give an id and a list of Movies, it extracts:
1) Nothing +the given list, if the id is found
2) Just + the movie , and the new list without that movie, if the given id is found, and the movie is deleted from the list
example:
*Main> extract 0 [(1,"Matrix",16),(2,"Gladiator",0)]
(Nothing,[(1,"Matrix",16),(2,"Gladiator",0)])
*Main> extract 1 [(1,"Matrix",16),(2,"Gladiator",0)]
(Just (1,"Matrix",16),[(2,"Gladiator",0)])
How should I define the function?
extract :: Id -> [Movie] -> (Maybe Movie, [Movie])
extract id [] = (Nothing, [])
extract id ((fid, n, f):list) | fid == id = (Just (fid, n, f), list)
| otherwise = (found, (fid, n, f):tail)
where (found, tail) = extract id list
type Dictionary = [(String, String)]
dict :: Dictionary
dict = ("Deutsch", "English"):[]
insert :: Dictionary -> (String,String) -> Dictionary
insert dict entry = dict ++ [entry]
One thing that I didn't find about the way lists work: Is it somehow possible to overwrite the existing dict with the entry added in insert? Or is it necessary to, in the next step, always write out the list that was put out by insert?
insert [("German", "English"), ("Hallo", "hello")] ("Versuch", "try")
So far, this is the only way I have been able to add something to the new list without losing the previous entry. However, next on the list of things to implement is a search command, so I wonder if I'd also have to write this out in the search function.
The idea of functional programming is in general that your data is immutable. This means once you have created a list, you can NEVER change that list. But you can copy that list, make modifications to it, and keep that as well.
So when you have a list like so
test = [1,2,3]
We can modify this by adding 4 to the start:
test2 = 4 : test
: called the cons operator, puts an element in front of a list. Do note that x:xs (the same as doing [x]++xs) has a better performance than doing xs++[x]
So now we have two bindings, one of test to [1,2,3] and one of test2 to [4,1,2,3]
Hope this clarifies things
To give a full example:
type Dictionary = [(String, String)]
insert :: Dictionary -> (String,String) -> Dictionary
insert dict entry = dict ++ [entry]
dict0 = [ ("Deutsch", "English") ]
dict1 = insert dict0 ("Hallo", "hello")
dict2 = insert dict1 ("Versuch", "try")
If you're new to functional programming, I would recommend reading Learn You a Haskell for Great Good , which is a fantastic (and free) book on how to use Haskell -- and functional programming in general.
It's not too tough to do this
import Data.List (lookup)
insert :: Eq a => (a,b) -> [(a,b)] -> [(a,b)]
insert (a,b) [] = [(a,b)]
insert (a,b) ((c,d):rest) = if a == c
then (a,b) : rest
else (c,d) : insert (a,b) rest
---
dict :: [(String, String)]
dict = [("Deutsch", "English")]
If you can't use Data.List then you can define lookup by
lookup :: Eq a => a -> [(a,b)] -> Maybe b
lookup _ [] = Nothing
lookup k ((a,b):rest) = if k == a then Just b else lookup k rest
Now if you load up GHCI:
>> let dict' = insert ("Ein","One") dict
>> dict'
[("Deutsch","English"),("Ein","One")]
>> lookup "Ein" dict'
Just "One"
>> insert ("Deutsch", "Francais") dict'
[("Deutsch","Francais"),("Ein","One")]
If you want to replace an existing pair with the same key then you could write insert as:
insert :: Dictionary -> (String, String) -> Dictionary
insert [] p = [p]
insert ((dk, dv):ps) p#(k, v) | dk == k = p:ps
insert (p:ps) ip = p : (insert ps ip)
However if you are writing an association list, then you can simplify it by inserting new items at the front of the list:
insert :: Dictionary -> (String, String) -> Dictionary
insert = flip (:)
if you then search from the front of the list, it will find any values added more recently first.
In Haskell, most values are immutable, meaning that you can not change their value. This seems like a huge constraint at first, but in reality it makes it easier to reason about your program, especially when using multiple threads.
What you can do instead is continually call insert on the dictionary returned when you call insert, for example:
mainLoop :: Dictionary -> IO ()
mainLoop dict = do
putStrLn "Enter the German word:"
german <- getLine
putStrLn "Enter the English word:
english <- getLine
let newDict = insert dict (german, english)
putStrLn "Continue? (y/n)"
yesno <- getChar
if yesno == 'y'
then mainLoop newDict
else print newDict
main = do
One simply can't 'overwrite' anything in a pure language (outside of ST monad). If I understood your question correctly, you are looking for something like this:
insert :: Dictionary -> (String,String) -> Dictionary
insert [] b = [b] -- If this point is reached where wasn't matching key in dictionary, so we just insert a new pair
insert (h#(k, v) : t) b#(k', v')
| k == k' = (k, v') : t -- We found a matching pair, so we 'update' its value
| otherwise = h : insert t b