Question

In: Computer Science

4. For each of the following haskell type declarations, declare an object of the type this....

4. For each of the following haskell type declarations, declare an object of the type this. a. type this = ([Bool], Float) b. type this = (Float, Integer) -> ([Float], Integer) c. data that = new Char | old Integer type this = [(Float, that)] d. type this = (a, b) -> (a, a)

Solutions

Expert Solution

Haskell is a purely functional language, all computations are done via the evaluation of expressions (syntactic terms) to yield values (abstract entities that we regard as answers). Every value has an associated type. (Intuitively, we can think of types as sets of values.) Examples of expressions include atomic values such as the integer 5, the character 'a', and the function \x -> x+1, as well as structured values such as the list [1,2,3] and the pair ('b',4).

Just as expressions denote values, type expressions are syntactic terms that denote type values (or just types). Examples of type expressions include the atomic types Integer (infinite-precision integers), Char (characters), Integer->Integer (functions mapping Integer to Integer), as well as the structured types [Integer] (homogeneous lists of integers) and (Char,Integer) (character, integer pairs).

All Haskell values are "first-class"---they may be passed as arguments to functions, returned as results, placed in data structures, etc. Haskell types, on the other hand, are not first-class. Types in a sense describe values, and the association of a value with its type is called a typing. Using the examples of values and types above, we write typings as follows:

5 :: Integer
'a' :: Char
inc :: Integer -> Integer
[1,2,3] :: [Integer]
('b',4) :: (Char,Integer)

The "::" can be read "has type."

Functions in Haskell are normally defined by a series of equations. For example, the function inc can be defined by the single equation:

inc n = n+1

An equation is an example of a declaration. Another kind of declaration is a type signature declaration (§4.4.1), with which we can declare an explicit typing for inc:

inc :: Integer -> Integer

For pedagogical purposes, when we wish to indicate that an expression e1 evaluates, or "reduces," to another expression or value e2, we will write:

e1 => e2

For example, note that:

inc (inc 3) => 5

Haskell's static type system defines the formal relationship between types and values (§4.1.4). The static type system ensures that Haskell programs are type safe; that is, that the programmer has not mismatched types in some way. For example, we cannot generally add together two characters, so the expression 'a'+'b' is ill-typed. The main advantage of statically typed languages is well-known: All type errors are detected at compile-time. Not all errors are caught by the type system; an expression such as 1/0 is typable but its evaluation will result in an error at execution time. Still, the type system finds many program errors at compile time, aids the user in reasoning about programs, and also permits a compiler to generate more efficient code (for example, no run-time type tags or tests are required).

Haskell type expressions

Syntax of Types

type   →   btype [-> type]   (function type)

btype   →   [btype] atype   (type application)

atype   →   gtycon
|   tyvar
|   ( type1 , … , typek )   (tuple type, k ≥ 2)
|   [ type ]   (list type)
|   ( type )   (parenthesised constructor)

gtycon   →   qtycon
|   ()   (unit type)
|   []   (list constructor)
|   (->)   (function constructor)
|   (,{,})   (tupling constructors)

The type system also ensures that user-supplied type signatures are correct. In fact, Haskell's type system is powerful enough to allow us to avoid writing any type signatures at all; (With a few exceptions to be described later.) we say that the type system infers the correct types for us. Nevertheless, judicious placement of type signatures such as that we gave for inc is a good idea, since type signatures are a very effective form of documentation and help bring programming errors to light.

Polymorphic Types

Haskell also incorporates polymorphic types---types that are universally quantified in some way over all types. Polymorphic type expressions essentially describe families of types. For example, (forall a)[a] is the family of types consisting of, for every type a, the type of lists of a. Lists of integers (e.g. [1,2,3]), lists of characters (['a','b','c']), even lists of lists of integers, etc., are all members of this family. (Note, however, that [2,'b'] is not a valid example, since there is no single type that contains both 2 and 'b'.)

Lists are a commonly used data structure in functional languages, and are a good vehicle for explaining the principles of polymorphism. The list [1,2,3] in Haskell is actually shorthand for the list 1:(2:(3:[])), where [] is the empty list and : is the infix operator that adds its first argument to the front of its second argument (a list). (: and [] are like Lisp's cons and nil, respectively.) Since : is right associative, we can also write this list as 1:2:3:[].

User-Defined Types

We can define our own types in Haskell using a data declaration, which we introduce via a series of examples (§4.2.1).

An important predefined type in Haskell is that of truth values:

data Bool = False | True

The type being defined here is Bool, and it has exactly two values: True and False. Type Bool is an example of a (nullary) type constructor, and True and False are (also nullary) data constructors (or just constructors, for short).

Similarly, we might wish to define a color type:

data Color = Red | Green | Blue | Indigo | Violet

Both Bool and Color are examples of enumerated types, since they consist of a finite number of nullary data constructors.

Here is an example of a type with just one data constructor:

data Point a = Pt a a

Because of the single constructor, a type like Point is often called a tuple type, since it is essentially just a cartesian product (in this case binary) of other types. (Tuples are somewhat like records in other languages.) In contrast, multi-constructor types, such as Bool and Color, are called (disjoint) union or sum types.

Note that the type of the binary data constructor Pt is a -> a -> Point a, and thus the following typings are valid:

Pt 2.0 3.0 :: Point Float
Pt 'a' 'b' :: Point Char
Pt True False :: Point Bool

On the other hand, an expression such as Pt 'a' 1 is ill-typed because 'a' and 1 are of different types.

It is important to distinguish between applying a data constructor to yield a value, and applying a type constructor to yield a type; the former happens at run-time and is how we compute things in Haskell, whereas the latter happens at compile-time and is part of the type system's process of ensuring type safety.

Recursive Types

Types can also be recursive, as in the type of binary trees:

data Tree a = Leaf a | Branch (Tree a) (Tree a)

Here we have defined a polymorphic binary tree type whose elements are either leaf nodes containing a value of type a, or internal nodes ("branches") containing (recursively) two sub-trees.

When reading data declarations such as this, remember again that Tree is a type constructor, whereas Branch and Leaf are data constructors. Aside from establishing a connection between these constructors, the above declaration is essentially defining the following types for Branch and Leaf:

Branch :: Tree a -> Tree a -> Tree a
Leaf :: a -> Tree a


With this example we have defined a type sufficiently rich to allow defining some interesting (recursive) functions that use it. For example, suppose we wish to define a function fringe that returns a list of all the elements in the leaves of a tree from left to right. It's usually helpful to write down the type of new functions first; in this case we see that the type should be Tree a -> [a]. That is, fringe is a polymorphic function that, for any type a, maps trees of a into lists of a. A suitable definition follows:

fringe :: Tree a -> [a]
fringe (Leaf x) = [x]
fringe (Branch left right) = fringe left ++ fringe right

Here ++ is the infix operator that concatenates two lists (its full definition will be given in Section 9.1). As with the length example given earlier, the fringe function is defined using pattern matching, except that here we see patterns involving user-defined constructors: Leaf and Branch. [Note that the formal parameters are easily identified as the ones beginning with lower-case letters.]

Type Synonyms

For convenience, Haskell provides a way to define type synonyms; i.e. names for commonly used types. Type synonyms are created using a type declaration. Here are several examples:

type String = [Char]
type Person = (Name,Address)
type Name = String
data Address = None | Addr String


Type synonyms do not define new types, but simply give new names for existing types. For example, the type Person -> Name is precisely equivalent to (String,Address) -> String. The new names are often shorter than the types they are synonymous with, but this is not the only purpose of type synonyms: they can also improve readability of programs by being more mnemonic; indeed, the above examples highlight this. We can even give new names to polymorphic types:

type AssocList a b = [(a,b)]

This is the type of "association lists" which associate values of type a with those of type b.


Related Solutions

Create an object called Circle. Declare the following integer variables for the object Circle, radius, diameter,...
Create an object called Circle. Declare the following integer variables for the object Circle, radius, diameter, and pi is declared as double. Create the following for the Circle object: ● Implicit constructor (default constructor) ● Void method Calculate (double pi, int radius) to calculate the area of the Circle object. The method must include a system.out statement that displays the area value. Use the following formula to calculate area of the circle: Area = pi * (r * r) Your...
Compare between document type declarations and document instance.
Compare between document type declarations and document instance.
Update the function playScratchOffs to do the following Declare an integer variable to store the type...
Update the function playScratchOffs to do the following Declare an integer variable to store the type of scratch off (i.e. type) Declare an integer variable to store the number of scratch off (i.e. count) Declare an integer variable for loop control (i.e. c) Declare a variable of data type struct OneDollar (i.e. oneSO) Declare a variable of data type struct TwoDollar (i.e. twoSO) Declare a variable of data type struct FiveDollar (i.e. fiveSO) Write a series of printf statements to...
There are two kinds of white dwarf stars. For each kind, explain the type of object...
There are two kinds of white dwarf stars. For each kind, explain the type of object it comes from and what it is made of, and how it is formed.
Python HW with Jupyter Notebook Declare a variable named DATA as a dictionary object. Assign the...
Python HW with Jupyter Notebook Declare a variable named DATA as a dictionary object. Assign the set of key/value pairs shown below. Create a function named iter_dict_funky_sum() that takes one dictionary argument.    Declare a running total integer variable. Extract the key/value pairs from DATA simultaneously in a loop. Do this with just one for loop and no additional forms of looping. Assign and append the product of the value minus the key to the running total variable. Return the funky...
C++ Please complete based on the code below. Declare another stack object to the code in...
C++ Please complete based on the code below. Declare another stack object to the code in main(). Add a stack operator called CopyStack to the Stack class which, when executed, copies the contents of the first stack into the second stack. Modify your menu so that this option is available. The menu should also allow the second stack to be printed, pushed, popped, and so forth, just like with the first stack. #include using namespace std; #define MAXSize 10 class...
Suppose an object is 4 sided marked as {1,2,3,.., 4. Now you toss this object 4...
Suppose an object is 4 sided marked as {1,2,3,.., 4. Now you toss this object 4 times. Let nS be the number of outcomes in this sample space. Let A be the event consisting of all outcomes in which 2 occurs at least once. How many outcomes are there in A? It is whole number. Computer follows comma rule when entering large numbers. For example, 1123 is entered as 1,123
Question: 3. Prepare balance sheets for the end of each semester. Edwina Haskell was an accomplished...
Question: 3. Prepare balance sheets for the end of each semester. Edwina Haskell was an accomplished high school student who looked forward to attending Southern New England University (SNEU). SNEU was unique in that it operated on a trimester basis, its policy was to actively foster independent development among the students. Edwina’s mother and father each own their own small businesses. Soon after freshman orientation at SNEU, Edwina recognized a need among the students that could be the basis for...
Write a Haskell function combine :: Int -> Int -> Int -> Int with the following...
Write a Haskell function combine :: Int -> Int -> Int -> Int with the following behavior: • When x, y, and z all correspond to digit values (i.e., integers between 0 and 9, inclusive), combine x y z returns the integer given by the sequence of digits x y z. (That is, x is treated as the digit in the hundreds place, y is treated as the digit in the tens place, and z is treated as the digit...
Write a java code segment to declare an array of size 10 of type String and...
Write a java code segment to declare an array of size 10 of type String and read data for them from a file, prompt user for the file name. Data is stored in a file with 1 string per line.
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT