-- CSCE 314 [Section 503] Programming Languages Spring 2021
-- Homework Assignment 1 (Total 130 points)

-- Problem 1 (5 points)
-- This is head comment (single line comment should be preceded by two dashes)
-- Student Name: Adam Taha
-- UIN: 428007900
-- 

-- On my honor, as an Aggie, I have neither given nor received any unauthorized
-- aid on any portion of the academic work included in this assignment.

module Main where

import Test.HUnit  -- if this line causes compile error, try the following
                   -- command at the terminal prompt > cabal v1-install HUnit
import System.Exit


-- Example:
-- Write a recursive function mySum that sums all the numbers
-- in a list without using the prelude function sum.
mySum :: [Int] -> Int  -- type signature of mySum. mySum accepts a list of Ints
                       -- as its argument and returns an Int
mySum []     = 0  -- def 1
mySum (x:xs) = x + mySum xs -- def 2

{- Block comment over multiple lines is enclosed within {- and -}
Explanation:
The type of mySum tells us that mySum takes a list of Ints as an argument
and returns an Int that is the sum of all the Ints in the argument list.

The def 1 of mySum is the base case of the recursion, that is,
the argument list is empty, for which case the function value is 
defined as zero (summation identity).

The def 2 is when the argument list contains at least one element, 
namely x, in which case the function is defined as the sum of x 
and the result of the recursive call of mySum applied to the rest of 
the argument list, namely xs.
-}


-- Problem 2 (10 points)
lucas :: Int -> Int
lucas n = if n == 0 then 2 
		  else if n == 1 then 1
			else lucas n-1 + lucas n-2



-- Problem 3 (5+5 = 10 points)
qsort1 :: Ord a => [a] -> [a]
---- Question 3.1 (5 points)
qsort1 [] = []
qsort1 (x:xs) = qsort1 larger ++ [x] ++ qsort1 smaller
                where
                    larger = [a | a <- xs, a >= x]
                    smaller = [b | b <- xs, b < x]


---- Question 3.2 (5 points)
{- Write your answer for Question 3.2 within this block comment.
	When the function qsort1 [3,2,3,1,4] is ran, [3,2,3,1,4] is taken in and is then split into the 'larger' section which is [4,3], the pivot x which equals 3,
	and the 'smaller' section which is equal to [2,1].
-}


-- Problem 4 (Chapter 5, Exercise 9) (10+5=15 points)
scalarproduct :: [Int] -> [Int] -> Int
---- Question 4.1 (10 points)
scalarproduct xs ys = sum [x * y | (x,y) <- zip xs ys]

---- Question 4.2 (5 points)
{- Write your answer for Question 4.2 within this block comment.

-}



-- Problem 5 (Chapter 6, Exercise 7) (10 points)
merge :: Ord a => [a] -> [a] -> [a]
merge = undefined



-- Problem 6 (Chapter 6, Exercise 8) (7+8=15 points)
halve :: [a] -> ([a], [a])  -- 7 points
halve = undefined


msort :: Ord a => [a] -> [a]  -- 8 points
msort = undefined



-- Problem 7 (10 points)
isElem :: Eq a => a -> [a] -> Bool
isElem = undefined


type Set a = [a]

-- Problem 8 (10 points)
toSet :: Eq a => [a] -> Set a
toSet = undefined


-- Problem 9 (10 points) Using isElement in the definition is required.
subset :: Eq a => Set a -> Set a -> Bool
subset = undefined


-- Problem 10 (10 points) Using subset in the definition is required.
setEqual :: Eq a => Set a -> Set a -> Bool
setEqual = undefined


-- Problem 11 (10+15=25 points)
powerset :: Set a -> Set (Set a)
---- Question 11.1 (10 points)
powerset = undefined

---- Question 11.2 (15 points)
{- Write your answer for Question 11.2 within this block comment.

-}



myTestList = 
  TestList [

      "lucas 1" ~: lucas 0 ~=? 2
    , "lucas 2" ~: lucas 1 ~=? 1    
    , "lucas 3" ~: lucas 4 ~=? 7
    
    , "qsort1 1" ~: qsort1 [3, 2, 5, 1, 6] ~=? [6,5,3,2,1]
    , "qsort1 2" ~: qsort1 "howdy" ~=? "ywohd"
    
    , "scalarproduct 1" ~: scalarproduct [4,5,6] [1,2,3] ~=? 32
    , "scalarproduct 2" ~: scalarproduct [2,3] [1,-1] ~=? -1
    , "scalarproduct 3" ~: scalarproduct [1..10] [1..5] ~=? 55

    , "merge 1" ~: merge "EGG" "ABCDEFGH" ~=? "ABCDEEFGGGH" 
    , "merge 2" ~: merge "Hello" "e" ~=? "Heello"

    , "halve 1" ~: halve "" ~=? ("","")
    , "halve 2" ~: halve "halves" ~=? ("hal","ves")
    , "halve 21" ~: halve "halve" ~=? ("ha","lve")

    , "msort 1" ~: msort "Howdy all!" ~=? " !Hadllowy"
    , "msort 2" ~: msort "" ~=? ""
    , "msort 3" ~: msort "Mississippi" ~=? "Miiiippssss"

    , "isElem 1" ~: (isElem 'h' "happy") ~=? True
    , "isElem 2" ~: (isElem 'o' "happy") ~=? False

    , "toSet 1" ~: length (toSet "aardvark") ~=? 5
    , "toSet 2" ~: length (toSet "BartBart") ~=? 4

    , "subset 1" ~: subset [] [1,2] ~=? True
    , "subset 2" ~: subset [1,2] [] ~=? False
    , "subset 3" ~: subset [2,3] [1,2] ~=? False
    , "subset 4" ~: subset [2,3] [3,1,2] ~=? True
    , "subset 5" ~: subset [2,3] [2,1,4] ~=? False

    , "setEqual 1" ~: setEqual "abc" "bca" ~=? True
    , "setEqual 2" ~: setEqual [1,2] [2,1] ~=? True
    , "setEqual 3" ~: setEqual [1,2,3] [1,2,3,4] ~=? False
    , "setEqual 4" ~: setEqual [2,3,1] [1,2,3] ~=? True

    , "powerset 1" ~: length (powerset ([]::[Int])) ~=? 1
    , "powerset 2" ~: length (powerset [5]) ~=? 2
    , "powerset 3" ~: length (powerset [3,2]) ~=? 4
    , "powerset 4" ~: length (powerset "abc") ~=? 8

    ]

main = do c <- runTestTT myTestList
          putStrLn $ show c
          let errs = errors c
              fails = failures c
          exitWith (codeGet errs fails)
          
codeGet errs fails
 | fails > 0       = ExitFailure 2
 | errs > 0        = ExitFailure 1
 | otherwise       = ExitSuccess