-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMain.hs
178 lines (155 loc) · 6.52 KB
/
Main.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
module Main (main) where
import System.IO
import System.Environment
import Test.QuickCheck
import Control.Monad (unless)
import Data.List ( transpose )
{-|
@author Santiago Benites fc54392
@author Joao Ferreira fc55312
-}
type Input = [Float]
type Value = Float
-- Data Types used to test the code
-- Creates a valid Float Array that represents various liens of the users input
data ValidInputArray = ValidInputArray { list :: [Input]} deriving Show
-- Creates a single line of the users input
data ValidInput = ValidInput { array :: Input} deriving Show
-- Creates a Int that can be used as a a valid position of the input
-- Used to reduce the number of discarded cases
data ValidInt = ValidInt { number :: Int} deriving Show
-- Arbitrary relative to ValidInput, creates a data type with a [Float]
instance Arbitrary ValidInput where
arbitrary = do
value <- (choose (1,10) :: Gen Int)
r <- rInput value
return (ValidInput r)
-- Arbitrary relative to ValidInputArray, creates a data type with a [Input]
instance Arbitrary ValidInputArray where
arbitrary = do
value <- (choose (1,10) :: Gen Int)
size <- (choose (1,10) :: Gen Int)
r <- vectorOf size (rInput value)
return (ValidInputArray r)
--Arbitrary relative to ValidInt, creates a data type with a Int
instance Arbitrary ValidInt where
arbitrary = do
r <- (choose (1,5) :: Gen Int)
return (ValidInt r)
-- Function that returns a Generator of valid inputs
-- Basicly a [Float] with length n where all the floats
-- have been truncated to 2 decimal places and are positive
rInput :: Int -> Gen Input
rInput n = do
r <- vectorOf n (arbitrary :: Gen Float)
return (fmap abs (fmap truncate' r))
-- truncates a float to 2 decimal places
truncate' :: Float -> Float
truncate' x = (fromIntegral (floor (x * t))) / t
where t = 10^2
main :: IO ()
main = do
hSetBuffering stdin NoBuffering
hSetBuffering stdout NoBuffering
testCheck <- getArgs
if( "-t" `elem` testCheck)
then do tests
else do -- ex:
line <- getLine -- sum 1 groupby 2
let input = words line -- ["sum", "1", "groupby", "2", "groupby", "4"]
function = getF $ head input -- sum
args = tail input -- ["1", "groupby", "2", "groupby", "4"]
columnNumber = read (head args) :: Int -- 1
groupby = s2I $ filter ("groupby" /=) (tail args) -- ["2", "4"]
applyMetrics function [] columnNumber groupby
{-| applyMetrics receives the input from the user and applies the
metric to it and the stored memory printing the result to stOut
Function receives as input:
f - Function that will be aplied to the
collumn of the restrictedList
xs- Matrix that represents past inputs
n - Collum of xs we want to input into f
c - Restricitons given by group by in Main
-}
applyMetrics :: ([Float] -> Float) -> [Input] -> Int -> [Int] -> IO ()
applyMetrics f xs n c = do
line <- getLine
unless (line == "exit") $ do
let input = s2f $ words line
memory = input:xs
restrictions = makeConstrictions c input
restrictedList = constrictions memory restrictions
print $ f (makeList restrictedList n)
applyMetrics f memory n c
{-| Receives matrix and returns a collumn in list
-}
makeList :: [Input] -> Int -> [Float]
makeList [] _ = []
makeList xs i = transpose xs !! i
{-| Receives list of ints and input and returns a pair, where the first element is
the int and the second is the value in the position int in the input.
-}
makeConstrictions :: [Int] -> Input -> [(Int,Float)]
makeConstrictions _ [] = []
makeConstrictions [] _ = []
makeConstrictions (x:xs) xy = (x, xy!!x) : makeConstrictions xs xy
{-| Applies restriction to a input and a pair (Int,Float) and
takes that input and aplies it to the next member of the [(Int,Float)] list
-}
constrictions :: [Input] -> [(Int,Float)] -> [Input]
constrictions [] _ = []
constrictions xs [] = xs
constrictions xs (x:c) = constrictions (restriction xs x) c
{-| Recieves a List of inputs and a pair type (Int,Float) and returns a list of
all the inputs of the list where the position int in the list is equal to the float.
-}
restriction :: [Input] -> (Int,Float) -> [Input]
restriction [] _ = []
restriction (x:xs) (a,b)
| a > length x = x:xs
| x !! a == b = x:restriction xs (a,b)
| otherwise = restriction xs (a,b)
{-| Recieves a String and a List of Floats and applies the
function represented by the string to the float list
-}
getF :: String -> Input -> Float
getF "maximum" = maximum
getF "sum" = sum
getF "average" = average
average :: [Float] -> Float
average [] = 0
average xs = sum xs / fromIntegral (length xs)
s2f :: [String] -> Input
s2f = map (read::String->Float)
s2I :: [String] -> [Int]
s2I = map (read::String->Int)
{-| Executes all the tests
-}
tests :: IO ()
tests = do
quickCheck prop_average_sum
quickCheck prop_restriction_length
quickCheck prop_makeList_loss
{-| Tests to see if adding 1 to all members of the input list and checks if the
average of the new list is larger that the original one
-}
prop_average_sum :: ValidInput -> Bool
prop_average_sum (ValidInput n) = average n <= average (map (+1) n)
minimumLength :: [[a]] -> Int -> Int
minimumLength [] acc = acc
minimumLength (x:xs) acc
| acc == 0 = minimumLength xs (length x)
| acc > length x = minimumLength xs (length x)
|otherwise = minimumLength xs acc
{-| Tests to see if the length of the list after restrictions
being applied is smaller or equal than it was before
-}
prop_restriction_length :: ValidInputArray -> ValidInt -> Float -> Property
prop_restriction_length (ValidInputArray n) (ValidInt x) y =
(x < minimumLength n 0) ==> length (restriction n (x,y)) <= length n
{-| Tests to see if the length of the list before being applied
makeList is equal to after it as been applied
-}
prop_makeList_loss :: ValidInputArray -> ValidInt -> Property
prop_makeList_loss (ValidInputArray xs) (ValidInt n) =
(n < minimumLength xs 0) ==> length (makeList xs n) == length xs