Population

Haskell Assignment

A.First Edition
This is second assignment of Haskell Assignment.
B.The problem
C.The idea of program
D.The major functions
C.Further improvement
It is a shameful thing to post it, however I have to do it, just record what I have done.
กก
Name: Qingzhe Huang
ID: 5037735
Title: Comp348 Assignment 2

> module A2 where

-------------------------------------------------------------------------------------------------

Question 1

I made two utility function to get min and max from a list of numbers

minlist :: Ord a => [a] -> a

> minlist (x:xs) = if xs == [] then x else if x <= minlist xs then x else minlist xs

maxlist :: Ord a => [a] -> a

> maxlist (x:xs) = if xs == [] then x else if x >= maxlist xs then x else maxlist xs

I have to define power as a normal function since there is no member functions like it in class Floating
power :: (Num a, Ord a) => Interval -> a -> Interval

> power (x:<x') n = if n==0 then  (1:<1) 
> 	else  
> 	if n>0 then (x:<x') * (power (x:<x') (n-1)) 	
>	else  recip (power (x:<x') (-n))

definitions:

(:<) :: Double -> Double -> Interval  -- data constructor 

> data Interval  =  Double :< Double

Show:

> instance Show Interval where
>	show  (x :< y)  = "<" ++ show  x ++ "," ++ show y ++ ">"

Eq class:

> instance Eq Interval  where
>   	(x:<x')==(y:<y') = (x==y)&&(x'==y')

Ord class: I made this in order to simplify comparison of cases of "Containing Zero": if (x:<x')>=(0:<0)

> instance Ord Interval where
>	(x:<x')>= (y:<y') = (x>=y&&x'>=y')
>	(x:<x')<= (y:<y') = (x<=y&&x'<=y')	

Num class:

> instance Num Interval where
>       (x:<x') + (y:<y') = (x+y):<(x'+y')

>	(x:<x') * (y:<y') = (minlist [x*y, x*y', x'*y, x'*y']):<(maxlist [x*y, x*y', x'*y, x'*y'])

>   	negate (x:<x') = (-x'):<(-x)

Fraction class:

> instance Fractional Interval where
> 	recip (x:<x') = if (x<=0&&x'>=0) then error "containing zero" 
>		else (1/x'):<(1/x) 

Floating class: since I implemented Ord class, I can use Interval comparison here.

> instance Floating Interval where
> 	sqrt (x:<x') = if ((x:<x')>=(0:<0)) then (sqrt x):<(sqrt x') 
>		else error "non-negative error"	

	
> zero = 0:<0
> containzero = (-2.4):<5.1
> negative = (-3.2):<(-4.5)
> positive = 9.0:<10.5

I like to have some message displaying on my screen

> test1 =  "The followings are all test for question 1"

> test1a = "show dividing by zero interval" ++ show (positive/zero) 
> test1b = "show dividing by interval containing zero" ++ show (positive/containzero) 
> test1c = "show taking the square root of a non-positive interval"++ show (sqrt containzero)
> test1d = "show taking the square root of zero interval  "++ show (sqrt zero)
> test1e = "show taking the square root of a negative interval"++ show (sqrt negative)
> test1f = "show rasing an interval containing zero to a negative power   "++show (power negative (-3))


-------------------------------------------------------------------------------------------------

Question 2


commutative :: Eq a => (b -> b -> a) -> b -> b -> c -> [Char]

> commutative op x y _ = if op x y == op y x then "" else " commutative law fails "

associative :: Eq a => (a -> a -> a) -> a -> a -> a -> [Char]

> associative op x y z = if op (op x y) z == op x  (op y z) then "" else " associative law fails "

check :: Num a => a -> a -> a -> [Char]

> check  x y z  = 
>	 commutative (+) x y z ++  
>	 commutative (*) x y z ++ 
>	 associative (+) x y z ++
>	 associative (*) x y z

> int1 = 2:<2
> int2 = 5:<5
> int3 = (-9):<(-9)

> float1 = 3.5:<4.3
> float2 = 2.1:<3.9
> float3 = (-10.0):<9.9

I like to have some message displaying on my screen

> test2 =  "The followings are all test for question 2"

> test2a = check int1 int2 int3
> test2b = check float1 float2 float3
> test2c = check int1 float2 float3
> test2d = check int3 float3 float2


-------------------------------------------------------------------------------------------------

Question 3

the accuracy is chosen for 1%

> e = 0.01


I made a utility function to generate a interval with input number "d" and a setup tolarence "e"
inter :: Double -> Interval

> inter d = (d*(1-e)) :< (d*(1+e))


this utility function checks the "a == 0" error and negative sqrt error
checkroot :: Double -> Double -> Double -> Bool

> checkroot a b c = if a==0 then error " a == 0 "
>		else if  power (inter b) 2 - (4:<4)*(inter a)*(inter c) < (0:<0) 
>		then error " sqrt for negatives " else True 

solve calculates the "root" with interval
solve :: Double -> Double -> Double -> (Interval,Interval)


> solve a b c = if checkroot a b c then 
>	((-(inter b)+sqrt ((inter b)*(inter b) - (4:<4)*(inter a)*(inter c)))/((2:<2)*(inter a)),
>	 (-(inter b)-sqrt ((inter b)*(inter b) - (4:<4)*(inter a)*(inter c)))/((2:<2)*(inter a)))
> 	else  error "error"

This root function calculates the real root
root :: Floating a => a -> a -> a -> (a,a)

> root a b c = ((-b+sqrt(b*b -4*a*c))/(2*a),(-b-sqrt(b*b -4*a*c))/(2*a))

test data is declared here: 

> num1 = [1.02, 2.9, 1.4]  
> num2 = [4.2, 100.3,(-3.9)]
> num3 = [1.001, 2.0003, 1.0001]

this function simply call both solve and root function with parameter of a list of numbers
assign :: [Double] -> [Char]

> assign (a:(b:([c]))) = show (solve a b c) ++ "compared with roots "++ show (root a b c)


I like to have some message displaying on my screen

> test3 =  "The followings are all test for question 3"

--num1 is common

> test3a = assign num1 

a) with b much greater than 1, the solution has less accuracy.

> test3b = assign num2  

b) with roughly a= b/2 = c, there is no solution for interval

> test3c = assign num3  



-------------------------------------------------------------------------------------------------

Question 4

a) eqrev :: Eq a => [a] -> Bool

> eqrev s = s == reverse s


b)lower :: [Char] -> [Char]

> lower s = map toLower s

c) letters :: [Char] -> [Char]

> letters s = filter isAlpha s

palindrome :: [Char] -> Bool

> palindrome = eqrev.lower.letters


> string1 = "Evil rats on no star live"
> string2 = "Able was I ere I saw Elba"
> string3 = "A man! A plan! A canal! Panama!"
> string4 = "This string is not palindromic."



I like to have some message displaying on my screen

> test4 =  "The followings are all test for question 4"
 
test4a :: [Bool]

> test4a = map palindrome [string1,string2, string3, string4]


--------------------------------------------------------------------------------------------------------------------------

Result of test:


A2> test1
"The followings are all test for question 1"
A2> test1a
"show dividing by zero interval
Program error: containing zero

A2> test1b
"show dividing by interval containing zero
Program error: containing zero

A2> test1c
"show taking the square root of a non-positive interval
Program error: non-negative error

A2> test1d
"show taking the square root of zero interval  <0.0,0.0>"
A2> test1e
"show taking the square root of a negative interval
Program error: non-negative error

A2> test1f
"show rasing an interval containing zero to a negative power   <-0.0305176,-0.01
09739>"
A2>
A2> test2
"The followings are all test for question 2"
A2> test2a
""
A2> test2b
" associative law fails  associative law fails "
A2> test2c
""
A2> test2d
" associative law fails "
A2> test3
"The followings are all test for question 3"
A2> test3a
"(<-0.680682,-0.555488>,<-2.30515,-2.14778>)compared with roots (-0.616393,-2.22
674)"
A2> test3b
"(<-0.202401,0.280826>,<-24.403,-23.4461>)compared with roots (0.03882,-23.9198)
"
A2> test3c
"(
Program error: non-negative error

A2> test4
"The followings are all test for question 4"
A2> test4a
[True,True,True,False]
A2>







			


                                 back.gif (341 bytes)       up.gif (335 bytes)         next.gif (337 bytes)