Suppose I define type
type person = { last_name: string; first_name: string; age: int};;
let person1 = {last_name="Doe"; first_name="John"; age=30};;
How can I print
Last name : Doe
First name : John
Age : 30
I thought using
match person1 with
| {last_name=ln; first_name=fn; age=a} -> print_string ...;;
but it seems not the way to go. If person1 and person were defined to be a dictionary with 1000 elements, then that solution doesn't hold.
Is there a better way to challenge that problem? Be aware that I have to use the functional paradigm. So I can't use while or for loop directly
It's hard to answer your question because you seem to have two different ideas of your type simultaneously. You can't have a type that's both a record and a dictionary. It's not possible.
Generally speaking, a dictionary is a collection of things. The convention for collections in OCaml is that they have a function named iter that traverses the collection.
Imagine you have an abstract collection defined by a module C. Conventionally you'll have a type 'a C.t for each collection, where 'a is the type of the elements of the collection. You'll also have (conventionally) a function C.iter of this type:
C.iter : ('a -> unit) -> 'a C.t -> unit
This means you can pass a function (like your printing function) to C.iter, and then also pass a collection. The iter function will traverse the collection and call your function for every element.
In your case the module C would define the dictionary you're imagining, and the type person C.t would be the type of a dictionary of the records you show above. The function C.iter would have the type (person -> unit) -> person C.t -> unit. In other words, it would take a function and apply it to all the persons in the dictionary, one after the other.
We can't really say more unless we know the details of the dictionary that you are planning to create.
Related
What is the difference between following two syntaxes.
(* First *)
type named = < age :int ;name :string >;;
(* Second *)
type named = {
age: int;
name: string
};;
I know the second one is a record but what is the first one, I just need to know a name that I can search online to learn more.
The first definition is an object type. The most significant difference is that objects are structural and late bound while records are nominal and early bound.
See the manual entries for records and objects for more details.
I'm trying to implement a function to add like terms of a sorted list of tuples (first number represents polynomial's constant, the second represents the power). I'm an ocaml noob and don't really know what I'm doing wrong or how to do this correctly.
I tried to write it, but it doesn't work
https://gyazo.com/d37bb66d0e6813537c34225b6d4048d0
let rec simp list =
match list with
| (a,b)::(c,d)::remainder where b == d -> (a+c,b)::simp(remainder)
| (a,b)::(c,d)::remainder where b != d -> (a,b)::(c,d)::simp(remainder)
| _ -> list;;
This should combine all the terms with the same second value and just return one tuple with their first values added to the new list. ie: [(3,2);(4,2)] -> [(7,2)].
I am not familiar with the where keyword - there is ocaml-where which provides it, but it seems to be doing something different than what you are expecting. As such, the syntax is just wrong, and where is unexpected.
You probably meant when instead of where.
So in an exercise I am given a list like ["xyz", True, 42]. The question was if that is a valid expression in Haskell and what the type of that expression is.
A list can only hold homogenous types but the type of "xyz"is [Char], the type of True is Bool and the type of 42 is Num p => p. That is different types so I can't put them into a list.
That's what I thought. But the given answer to that exercise is "Yes, it is a valid expression. Show-instance!."
Why is it a valid expression although the types of the list elements are different and what is meant with show-instance? I'm thinking of something like superclasses from object oriented languages but I thought this is not how Haskell works.
If we are allowed to define some more context, we can make this a valid expression, for instance with:
import Data.String(IsString(fromString))
instance IsString Bool where
fromString [] = False
fromString _ = True
instance Num Bool where
(+) = (||)
(*) = (&&)
abs = id
signum = id
fromInteger 0 = False
fromInteger _ = True
negate = not
(here I used the truthiness of Python to convert from an Integer and String literal)
Then we can write it with the OverloadedStrings pragma:
{-# LANGUAGE OverloadedStrings #-}
the_list = ["xyz", True, 42]
This will then be equivalent to:
Prelude Data.String> ["xyz", True, 42]
[True,True,True]
But note that the list still contains only Bools, we only made Bool an instance of IsString and Num to enable us to convert string literals and number literals to Bools.
A list of heterogeneous types is not possible in Haskell, and since by default a Bool is not a Num, we thus can not parse that expression without adding some extra magic.
An additional note is that it is valid Haskell grammar: syntactically there is nothing wrong, it is only in the next stage of the compiler: type checking, etc. that it will raise errors, since the syntax is nonsensical.
My lecturer gave me a hint to check for Existential types in Haskell.
I produced a working example from the description from the link above:
{-# LANGUAGE ExistentialQuantification #-}
module Main where
data Showable = forall a . Show a => MkShowable a
pack:: Show a => a -> Showable
pack a= MkShowable a
instance Show Showable where
show (MkShowable a) = show a
hlist :: [Showable]
hlist = [pack "xyz", pack True, pack 42]
main :: IO ()
main = do
putStrLn "Heterogenous list 'camouflaged' as Showable:"
print hlist
This works and produces indeed the input from the exercise. The datatype extension for Existential Quantification in the first line is necessary.
My explanation (I might have gotten something wrong though):
I create a new type Showablewith one constructor MkShowable that takes any value a as long as it is in typeclass Show and thus makes a Showable out of it.
The method pack makes a Show a become a Showable by using the constructor MkShowable I described in 1.
Showable is made an instance of Show-typeclass and tells that if a Showable(MkShowable a) is to be shown, simply show a. So we can easily print our Showables.
Furthermore I created a (heterogenous) list hlist of type [Showable]and packed the values from my example into it, using pack. The list is printed in the main function.
This really reminds me of object-oriented programming.
I am a beginner in Haskell and trying to learn it, so please excuse my obliviousness.
I am currently trying to implement a Telephone book, which is a List of tuples [(Name, Number)] (Both are Strings).
type TelephoneBook = [(String),(String)] (?)
However, I have no clue how I can extend this list by another tuple.
For example: [("Fred", "47/273")] and now I want to add another tuple.
I was trying to understand how the module dictionary works to see how I can extend this List and I stumbled upon "data" and "type".
An idea I had was to create a several types of this TelephonBook:
let a = TelephoneBook ("Fred","42/2321")
but that is just a simple idea... I am kinda lost on how to extend this list by another tuple, taking into account that once something is defined it can't be altered (or can it).
(Please don't give the solution to the Problem but simply an idea on how to start or what I should Research further)
The (:) operator prepends elements to lists. For example:
> ("John", "555-1212") : [("Fred", "42/2321")]
[("John","555-1212"),("Fred","42/2321")]
because you're asking to extend a list:
i have to disappoint you. That's not possible in Haskell. You can construct a new one. Out of one Element and another List.
the list type in Haskell is defined similar to:
-- 1 2 3 4
data [a] = a : [a] | []
-- 1: if you encounter the type [a]
-- 3: it is either
-- 2: an element `e` and a list `l` forming the new list `e:l`
-- 4: or an empty List `[]`
-- so the types of the constructors are:
-- (:) :: a -> [a] -> [a]
-- [] :: [a]
So having a new element and a list you can construct a new one, using (:)!
type Entry = (String, String)
type Book = [Entry]
addEntry :: Entry -> Book -> Book
addEntry e b = e : b -- this works, because book is just a list
-- without type aliases: (this is the same, but maybe slightly less nice to read)
addEntry' :: (String, String) -> [(String, String)] -> [(String, String)]
addEntry' e b = e : b
-- or even simpler:
addEntry'' = (:)
The type keyword in Haskell has to be understood as a type alias, so it's just another name for something, the representation in Haskell is the same.
I have:
type Person = String
type Book = String
type Database = [(Person,[Book])]
I'm trying to define a function:
books :: Database -> Person -> [Book]
that takes in
1) a list of tuples (which contain a string and a list of strings
2) a String name
and returns a list of strings (namely the books from the database)
I want to use list comprehension, but I don't know how to access elements within a list that is in the tuple inside of the database list.
Thoughts?
Example database would look like:
db = [("Bob", ["Red Riding Hood", "Alice in Wonderland"]), ("Carol", ["Game of Thrones"])]
And if I ask for say "Carol", it should return ["Game of Thrones"].
Since you have an association list you can use the lookup function. It pretty much works exactly like you want:
getVal :: Database -> String -> Maybe [String]
getVal = lookup
The only difference is that it returns a Maybe but IMHO that is the right behavior, consider what would happen if you didn't have a value in your database when you looked it up?
Since you want to use pattern matching here is the source of lookup
lookup :: (Eq a) => a -> [(a,b)] -> Maybe b
lookup _key [] = Nothing
lookup key ((x,y):xys)
| key == x = Just y
| otherwise = lookup key xys
Or in your case
getVal :: Database -> String -> [String] --Avoids a Maybe if you want
getVal _key [] = []
getVal key ((x,y):xys)
| key == x = y
| otherwise = getVal key xys
As the other posters said, lookup is the way to go here: it's the standard procedure to search for something in an association list.
That said, a solution using a list comprehension would be
books :: Database -> Person -> [Book]
books db authorName = [book | (author, bookName) <- db,
author == authorName
book <- bookName]
It's taking out (author, bookName) tuples one by one, discarding the ones where the author doesn't match. If then adds the books of that author to the result.
Again, this implements a sort-of workaround for a function that's already in the standard libraries, and it's less readable in general. Really, use lookup.
I wouldn't use a list comprehension for implementing that function - list comprehensions are better suited for building lists.
What you are looking for is the Prelude function lookup:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
As you can see it almost has the correct type, if a ~ Person and b ~ [Book] and after swapping the arguments. Since you want [Book] back and not Maybe [Book] you can wrap the whole thing inside fromMaybe, resulting in:
books db = fromMaybe [] . flip lookup db