Instructions
Objective
Write a program that allows users to simulate regular expressions in Haskell language.
Requirements and Specifications
Define a function sublistI2J that returns a sublist of an input list s.t. the items are in the original order and the first item is at a first index argument, inclusively and the last item is immediately before the second given index, EXclusively Examples:
sublistI2J 1 4 [0,1,2,3,4,5,6] == [1,2,3]
sublistI2J 4 1 [0,1,2,3,4,5,6] == [] -- return empty list if i>=j
sublistI2J 1 1 [0,1,2,3,4,5,6] == [] -- return empty list if i>=j
sublistI2J 1 4 "abcdefghi" == "bcd" -- works on any list
sublistI2J 2 6 "fred" == "ed" -- ok if j is greater than list length
sublistI2J 1 4 [] = [] -- also, if start < length, return []
Implement a function to tell if the first argument is a subsequence of the second. A subsequence here will be a list having items in the same order as the second argument but with possible gaps, i.e. It may involve skippiing items in the second list.
Important: the ORDER matters Examples:
subseq [2,4,8] [1..10] == True
subseq "red" "freddy" == True
subseq "der" "freddy" == False -- order matters
sebseq "fey" "freddy" == True -- gaps are okay
subseq [] [1..10] == True -- [] is a subseq of all sequences
Screenshots of output

Source Code
module FinalExamF20 where
{- Rules, a FEW of which you should have explicitly confirmed with the
online quiz, but other pointers and rules too:
0. You are responsible for checking your final submission to GitHub
or uploading the files to Blackboard if there is an issue (as a .zip)
1. You will lose at least half the points if you do not use the requested
language feature (recursion, patter matching, etc.), if one was
requested.
2. Small, i.e. 5 point questions, will not be graded for partial credit
-> You either solved it or you did not.
3. Use of a where or helper function is basically always legal EXCEPT
if you use it to avoid solving the problem as stated for problems
having a stated required feature to use. The litmus
test for this is tolerant -- if your use of the requested feature does
USEFUL work, then that is sufficient.
4. You may NOT import any libraries to solve any of these, besides
the Standard Prelude, which is loaded by default
5. The associated unit tests are not guarantees of a final score. I will
look at these files to make sure you follow the instructions, etc.
6. I am including the length of my solutions, in lines (80 char width max).
Most of my answers are really short. The shortest ones often use
higher order functions and/or standard prelude functions we used a lot.
7. You may of course "reformat" a parameter such as converting
length' xs = ...
to
length' (x:xs) = ...
and add additional base cases, etc. (and this will be necessary)
but do not REORDER the arguments or CHANGE the types
-}
{- (q1, 5pts) Implement logical exclusive-or, xor, with one or more
conditional statements. You may not, of course, use standard prelude
xor.
(My answer length = 1 line)
-}
xor :: Bool -> Bool -> Bool
xor x y = x /= y
{-(q2, 5pts) Using pattern matching,
and returns the minimum grade for that letter grade, i.e.
A is 89.5
B is 79.5
C is 69.5
D is 59.5
F is 0.0
(My answer length = 5 lines)
-}
minGrade :: Char -> Float
minGrade 'A' = 89.5
minGrade 'B' = 79.5
minGrade 'C' = 69.5
minGrade 'D' = 59.5
minGrade 'F' = 0.0
{- (q3, 5pts) Using a guarded equation, define a letterGrade functions
That takes a floating point number grade [0.0, 100.0]
and returns the letter grade corresponding to the number grade
Hint: see above (assuming it passes the tests)
Note: An 89.5 is an A, not a B but an 89.49 is a B
(My answer length = 6 lines)
-}
letterGrade :: Float -> Char
letterGrade grade
| grade >= 89.5 = 'A'
| grade >= 79.5 = 'B'
| grade >= 69.5 = 'C'
| grade >= 59.5 = 'D'
| otherwise = 'F'
{- (q4, 5pts) Give a lambda expression to define flipFirstTwo that takes
a single argument list and returns a new list such that it
returns a new list the same as the first list except that
the first two items are flipped -- meaning they have changed
places in the output list
examples:
flipFirstTwo [1..5] == [2,1,3,4,5]
flipFirstTwo "fred" == "rfed"
(My answer length = 1 line)
-}
flipFirstTwo :: [a]->[a]
flipFirstTwo = \xs -> (reverse (take 2 xs)) ++ (drop 2 xs)
{- (q5, 5 pts)
Use a list comprehension to capitalize all the 'i' characters in an input
string. Uppercase 'I's should remain the same. Examples:
capitalizeIs "capitalization is annoying" == "capItalIzatIon Is annoyIng"
capitalizeIs "I do not like green eggs." == "I do not lIke green eggs."
(My answer length = 1 line)
-}
capitalizeIs :: String -> String
capitalizeIs cs = [if c == 'i' then 'I' else c | c <- cs]
{- (q6, 5 pts) Use one or more list comprehensions to define a
multRange function that takes in three Int arguments:
o the first is an Int that is used to test for multiples of a number
o the second is the minimum, INclusive, multiple
o the third is the maximum, EXclusive, multiple
o Examples:
multRange 2 0 10 == [0,2,4,6,8] -- NO 10
multRange 5 1 20 == [5,10,15] -- NO 20 (no 0 either...)
Note/Reminder: We do not consider arithmetic sequences, e.g.
[1..10]
to be list comprehensions (but you may use one, a monor hint)
(My answer length = 1 line)
-}
multRange :: Int -> Int -> Int -> [Int]
multRange m l h = [ i | i <- [l..(h - 1)], i `mod` m == 0]
{-(q7, 5 points) Use RECURSION to tell if two strings have the same character
at the same index. You may not assume that the strings have the same
length. Examples:
sameXAtSameIndex "Irene" "Igloo" == True
sameXAtSameIndex "Irene" "irene" == True
sameXAtSameIndex "Irene" "Catalyst" == False
sameXAtSameIndex "Hippopotamus" "Apoptosis" == True
sameXAtSameIndex [] "Fred" = False
sameXAtSameIndex "" "Fred" = False
(My answer length = 3 lines)
-}
sameXAtSameIndex :: String-> String->Bool
sameXAtSameIndex [] _ = False
sameXAtSameIndex _ [] = False
sameXAtSameIndex (x:xs) (y:ys) = x == y || sameXAtSameIndex xs ys
{-(q8, 5 pts) Use a higher order function
(map, filter, or foldr sufficient)
to define a function that
returns true if all the even numbers in a list are also
multiples of 3. Examples:
evensMultOf3 [1,2,3,4] == False -- because of 2, 4
evensMultOf3 [1,2,3,5,6] == False -- because of 2
evensMultOf3 [1,3,5,7] == True -- no evens
evensMultOf3 [0,1,3,5,6, 9, 12] == True
(My answer length = 1 line)
-}
evensMultOf3 :: [Int] -> Bool
evensMultOf3 ns = and (map (\x -> mod x 3 == 0) (filter even ns))
{- (q9, 10pts)
Use a higher order function
(map, filter, or foldr sufficient)
to define a function that returns the maximum value in a list
or a given minumum value, if there does not exist a value in the list
greater than the minimum.
You may use standard prelude max, with type
max :: Ord a => a -> a -> a
but may NOT use standard prelude maximum
(which would make it hard to use a higher order function)
Examples:
maxOrMin 0 [1..10] == 10
maxOrMin 0 [-1,-2,-3] == 0
maxOrMin 20.0 [1.0,2.0,3.0,2.0,1.0] == 20.0
maxOrMin 20.0 [10.0,20.0,30.0,20.0,10.0] == 30.0
Hint: the output is a single value
(My answer length = 1 line, 43 characters, long variable names)
-}
maxOrMin :: (Ord a,Num a) => a -> [a] -> a
maxOrMin minimum ns = foldr max minimum ns
--Tree type for following question
--Note that this is slightly different than the one in book and
-- presented in class. There is no Leaf constructor. Nil is like null
-- in Java/C++
-- no duplicates in these trees (you don't need to test for that)
-- You should NOT change the type or any of the following tree definitions
-- Feel free to use a 'let' in GHCi to define others or define with your code
--
-- Note: I will define some other Trees in MY final tests, so pattern
-- matching them will fail and this question will get a 0.
data Tree a = Nil
| Node (Tree a) a (Tree a) deriving ShowgoodBST :: Tree Int
goodBST = Node (Node (Node Nil 1 Nil)3 Nil ) 5 (Node (Node Nil 6 Nil)7(Node Nil 9 Nil))
-- look at root
badBST1 :: Tree Int
badBST1 = Node (Node (Node Nil 1 Nil)3 Nil ) 2 (Node (Node Nil 6 Nil)7(Node Nil 9 Nil))
badBST2 :: Tree Int
badBST2 = Node (Node (Node Nil 1 Nil)3 Nil ) 5 (Node (Node Nil 6 Nil)111(Node Nil 9 Nil))
emptyBST :: Tree Int
emptyBST = Nil
{- end of Given Tree code
(don't change anything above this but before above comment)
-}
{- (q10,10) Solve the following problem anyway that makes sense.
implement a validBST function that returns true if the tree is a
valid binary search tree (BST). A BST is valid iff
1) each Node is greater than all of its left Node descendants
2) likewise each Node is less than all of its right Node descendants
3) a Nil is a valid BST (trivially)
4) you may assume there are no duplicates in the tree
Examples (see above for goodBST, badBST1, etc. definitions):
validBST goodBST == True
validBST badBST1 == False
validBST badBST2 == False
validBST emptyBST == True
Hint: for most of our examples pattern matching the CONSTUCTOR is
part of the answer, as in the examples given in class.
(My answer length = 8 lines with a where and a helper function...)
-}
validBST :: Ord a => Tree a -> Bool
validBST Nil = True
validBST (Node s a t) = lt a s && gt a t && validBST s && validBST t
where
lt v Nil = True
lt v (Node l w r) = (lt v l) && w < v && (lt v r)
gt v Nil = True
gt v (Node l w r) = (gt v l) && w > v && (gt v r)
{- (q11, 10) Free form (any approach)
Define a function sublistI2J that returns a sublist
of an input list s.t. the items are in the original order
and the first item is at a first index argument, inclusively
and the last item is immediately before the second given index, EXclusively
Examples:
sublistI2J 1 4 [0,1,2,3,4,5,6] == [1,2,3]
sublistI2J 4 1 [0,1,2,3,4,5,6] == [] -- return empty list if i>=j
sublistI2J 1 1 [0,1,2,3,4,5,6] == [] -- return empty list if i>=j
sublistI2J 1 4 "abcdefghi" == "bcd" -- works on any list
sublistI2J 2 6 "fred" == "ed" -- ok if j is greater than list length
sublistI2J 1 4 [] = [] -- also, if start < length, return []
(My answer length = 1 line )
-}
sublistI2J :: Int -> Int -> [a] -> [a]
sublistI2J i j xs = [x | (k,x) <- (zip [0..] xs), k >= i && k < j]
{- (q12, 10) Freestyle (any approach)
Implement a function to tell if the first argument is a subsequence
of the second. A subsequence here will be a list having items in the
same order as the second argument but with possible gaps, i.e.
it may involve skippiing items in the second list.
Important: the ORDER matters
Examples:
subseq [2,4,8] [1..10] == True
subseq "red" "freddy" == True
subseq "der" "freddy" == False -- order matters
sebseq "fey" "freddy" == True -- gaps are okay
subseq [] [1..10] == True -- [] is a subseq of all sequences
(My answer length = 3 lines)
-}
subseq:: Eq a => [a] -> [a] -> Bool
subseq [] bs = True
subseq as [] = False
subseq (a:as) (b:bs) = if a == b then subseq as bs else subseq (a:as) bs