Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

COM00025I

BEng, BSc, MEng and MMath Degree Examinations 2022-23

Computer Science

Software 3 - Formative 1

1       (40 marks)     Short questions

(i)      [1 mark]

Consider:

type  Predicate  a  =  a  ->  Bool

Write a function isPass that takes a list of integers and returns True if the sum is greater than or equal to 40 and False otherwise. Your solution should satisfy:

testP   ::  Bool

testP  =   (isPass   []  ==  False)  &&

(isPass   [2,  5,  6,  7]  ==  False)  &&

(isPass   [12,  15,  16,  17]  ==  True)  &&

(isPass   [5,  8,  12,  15]  ==  True)

(ii)     [1 mark]

Consider:

type  Predicate  a  =  a  ->  Bool

Write a function isAlphabet that takes a string and returns True if the string has only Latin alphabetic characters (as used for standard English) and False otherwise.

Your solution should satisfy:

testAl   ::  Bool

testAl  =   (isAlphabet  ""  ==  True  )  &&

(isAlphabet  "hello!"  ==  False)  &&

(isAlphabet  "hello"  ==  True)  &&

(isAlphabet  "Hello"  ==  True)  &&

(isAlphabet  "SOF3"  ==  False)  &&

(isAlphabet  "Software"  ==  True)

(iii)    [2 marks]

Write a function cmbList, such that, given two lists, it returns a single list with all

odd-position elements taken from the first list and even-position elements from the second list. Elements of the result appear in the same order that they do in the appropriate input list.

Note, lists are 0-indexed.

Your solution should satisfy:

testcmbList   ::  Bool

testcmbList  =

(cmbList   [’s’]  "comp"    ==  "cs")  &&

(cmbList  "otae""sfwr"  ==  "software")  &&

(cmbList   [1,  3,  5]   [0,  2,  4,  6]    ==   [0,1,2,3,4,5])  &&

(cmbList   ["1",  "2",  "3"]["THE",  "SOF",  "SYS"]  ==

["THE","1","SOF","2","SYS","3"])

(iv)    [2 marks]

Given two lists over a Num type, x, return a single list whose length is the same as the       minimum of the two and each element is the product of the numbers at the same position from the two lists.

Your solution should satisfy:

testcmbProd   ::  Bool

testcmbProd  =

(cmbProd   []   [5,  6]    ==   [])  &&

(cmbProd   [2,  3,  4]   [5,  6]    ==   [10,18])  &&

(cmbProd   [0 .23,  3 .4,  7 . 88,  9 .21]   [3 .4,  5]  ==   [0 .782,17 . 0])  && (cmbProd   [0 .23,  3 .4,  7 . 88,  2 *0 .3]   [3 .4,  1 .3,  2 . 1,  2]    ==           [0 .782,4 .42,16 .548000000000002,1 .2])

(v)     [3 marks]

Write a function sqDiff that returns a list of squares of the difference between two            consecutive numbers in a list, where the rst number is greater than the second number in the list. Your solution should satisfy:

testsqDiff   ::  Bool

testsqDiff  =

(sqDiff   []                                  ==   [])  &&

(sqDiff   [4,  6]                         ==   [])  &&

(sqDiff   [6,  4]                         ==   [4])  &&

(sqDiff   [4,  6,  3,  1,  8]    ==   [9,  4])

(vi)    [3 marks]

Write a function maybe2int::     [Maybe  Int]  ->  Int, which returns the sum of all

the integers in the list. The presence of Nothing values does not affect the result. Your solution should satisfy:

testM2int   ::  Bool

testM2int  =

(maybe2int   []                  ==  0)  &&

(maybe2int   [Just  23]  ==  23)  &&

(maybe2int   [Nothing]  ==  0)  &&

(maybe2int   [Just  2,  Nothing,  Just  3,  Just  16,  Nothing]  ==  21)

(vii)   [4 marks]

Write a function cmb   ::    Num  a  =>  String  ->   [a]  ->   [a]  ->   [a], which      returns a list twice as long as the shorter of the two input lists with all odd-position elements taken from the rst list and even-position elements from the second list when the string is    "List" or the product of the numbers at the same position from the two lists when the string is "Prod". Any other string apart from "Prod" and "List" returns an empty list.

Your solution should satisfy:

testcmb   ::  Bool

testcmb  =   (cmb  "Hello"   []   []  ==   [])  &&

(cmb  "Prod"   [2,  3]   []  ==   [])  &&

(cmb  "List"   []   [2,  3]  ==   [])  &&

(cmb  "Prod"   [2,  3,  4]   [5,  6]  ==   [10,18])  &&

(cmb  "List"   [2,  3,  4]   [5,  6]  ==   [5,2,6,3])  &&

(cmb  "Haskell"   [2,  3,  4]   [5,  6]  ==   [])  &&

(cmb  "Prod"   [2,  3,  4]   [5,  6,  7]  ==   [10,18,28])  &&

(cmb  "List"   [2,  3,  4]   [5,  6,  7]  ==   [5,2,6,3,7,4])

(viii)  [8 marks]     Consider the type of Stage 1 students record CS1:

data  CS1  =  Student   {name   ::  String,  the1,  sof1,  sys1   ::  Int}

A section of records for ve Stage 1 students are available in the database s1Db. Each record for a student has the student’s name and marks for three modules (THE1, SOF1 and SYS1).

s1Db   ::   [CS1]

s1Db  =   [Student   {name  =  "Beth",  the1  =  65,  sof1  =  58,  sys1  =  79}, Student   {name  =  "Adam",  the1  =  55,  sof1  =  68,  sys1  =  61},

Student   {name  =  "Lisa",  the1  =  60,  sof1  =  72,  sys1  =  65}, Student   {name  =  "Will",  the1  =  71,  sof1  =  52,  sys1  =  49}, Student   {name  =  "Mark",  the1  =  67,  sof1  =  78,  sys1  =  50}]

(a)  [2 marks]

Write a function the1Mk that takes any CSYear1 records like s1Db and returns a list of pairs of the name and THE1 mark of each student in the same order as they appear in the database.

Your solution should satisfy:

test1MK   ::  Bool

test1MK  =  the1Mk  s1Db  ==   [("Beth",65),("Adam",55),                       ("Lisa",60),("Will",71),("Mark",67)]

(b)  [3 marks]

Write a function tSOF1 that takes s1Db and return a list of tuples of the name, SYS1

mark and THE1 mark for all students who scored more than 70 in SOF1. Your solution should satisfy:

testSOF1::  Bool

testSOF1  =  tSOF1  s1Db  ==

[("Lisa",65,60),("Mark",50,67)]

(c)  [3 marks]

Write a function avgSYS1 that returns the average mark for SYS1.

Your solution should satisfy:

testavg::  Bool

testavg  =  avgSYS1  s1Db  ==  60 . 8

(ix)    [4 marks]

Write a function vowelDigit which returns True when applied to a string with alternating vowels and digits and False otherwise. The vowel comes rst in each pair and the input list must have even length. Your solution should satisfy:

testvowelDigit   ::  Bool

testvowelDigit  =

(vowelDigit  "  "                  ==  False)  &&

(vowelDigit  "a2"                ==  True)  &&

(vowelDigit  "aa22"           ==  False)  &&

(vowelDigit  "a2a2"           ==  True)  &&

(vowelDigit  "b2b2"           ==  False)  &&

(vowelDigit  "a2a21"         ==  False)  &&

(vowelDigit  "2a4o"           ==  False)  &&

(vowelDigit  "a2ab2"         ==  False)  &&

(vowelDigit  "a2o5u8A0"  ==  True)  &&

(vowelDigit  "b2o5u8A0"  ==  False)

(x)     [7 marks]     Consider:

data  BinTree  x  =  Lf  Int   |  Branch   (BinTree  x)  x   (BinTree  x) deriving   (Eq,  Show)

A tree is balanced if the length of the path from the root to the deepest leaf on the left is the same as the right and each subtree has the same structure. For a "Length-regular" tree, the  value at a leaf is the length of the path to the leaf.

(a)  [1 mark]

Define ‘nullBR‘ to be the smallest possible balanced, length-regular tree.

(b)  [4 marks]

Write a function isTreeBal which returns True when applied to a balanced tree,    and False otherwise. Remember, for a length-regular, balanced tree the value in a leaf is the length of the path from the root to the leaf. You can assume that the tree is        length-regular when testing balance.

Your solution should satisfy:

testBal   ::  Bool

testBal  =   (isTreeBal   (nullBR)  ==  True  )  &&

(isTreeBal   (Branch   (Lf  1)  1   (Branch   (Lf  2)  2   (Branch   (Lf  3)  3   (Lf  3)))) ==  False  )  &&

(isTreeBal   (Branch   (Branch   (Lf  2)  1   (Lf  2))  2   (Branch   (Lf  2)  3   (Lf  2))) ==  True  )

(c)  [2 marks]

Write a function treeNodes which returns the total number of interior nodes in a given tree. Note, the tree need not be balanced.

Your solution should satisfy:

testN   ::  Bool

testN  =

(treeNodes  nullBR  ==  0)  &&

(treeNodes   (Branch   (Lf  1)  3   (Lf  1))  ==  1)  &&

(treeNodes   (Branch   (Lf  1)  3   (Branch   (Lf  2)  8   (Lf  2)))  ==  2)  &&

(treeNodes   (Branch   (Lf  1)  1   (Branch   (Lf  2)  2   (Branch   (Lf  3)  3   (Lf  3))))  ==  3) &&

(treeNodes   (Branch   (Branch   (Lf  2)  1   (Lf  2))  2   (Branch   (Lf  2)  3   (Lf  2)))  ==  3)

(xi)    [5 marks]

Write a function toBarcode that takes a binary string (a string composed of 0s and 1s only) as parameter and returns a string representing a bar-code. The 0s are transformed into ’.’ and 1s into ’|’ . In addition, the function must return Nothing if the string contains a character that

is not a 0 or a 1. You can also assume that a string (including an empty string) is always given. Your solution should satisfy:

testBcode::  Bool

testBcode  =

(toBarcode  ""         ==  Just  "")  &&

(toBarcode  "00"  ==  Just  " . . ")  &&

(toBarcode  "1111"  ==  Just  " | | | | ")  &&

(toBarcode  "0010111"  ==  Just  " . . | . | | | ")  &&

(toBarcode  "01120"  ==  Nothing)  &&

(toBarcode  "  "  ==  Nothing)