-
Notifications
You must be signed in to change notification settings - Fork 0
/
4.4.hs
215 lines (162 loc) · 8.28 KB
/
4.4.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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
module Demo where
import Data.List.Split
import Data.Char
{-
Реализуйте функцию parsePerson, которая разбирает строки вида firstName = John\nlastName = Connor\nage = 30 и возвращает либо результат типа Person, либо ошибку типа Error.
Строка, которая подается на вход, должна разбивать по символу '\n' на список строк, каждая из которых имеет вид X = Y. Если входная строка не имеет указанный вид, то функция должна возвращать ParsingError.
Если указаны не все поля, то возвращается IncompleteDataError.
Если в поле age указано не число, то возвращается IncorrectDataError str, где str — содержимое поля age.
Если в строке присутствуют лишние поля, то они игнорируются.
-}
data Error = ParsingError | IncompleteDataError | IncorrectDataError String deriving Show
data Person = Person { firstName :: String, lastName :: String, age :: Int } deriving Show
parsePerson :: String -> Either Error Person
parsePerson = asPerson . validatedAge . validatedData . mappedPairs . validatedPairs . parsedPairs . validatedLines . parsedLines
asPerson :: Either Error [(String,String)] -> Either Error Person
asPerson (Left a) = Left a
asPerson (Right mps) =
Right (Person {
lastName = keyValue "lastName",
firstName = keyValue "firstName",
age = read $ keyValue "age"
})
where
keyValue = valueFromPairWithKey mps
validatedAge :: Either Error [(String,String)] -> Either Error [(String,String)]
validatedAge (Left a) = Left a
validatedAge (Right mps) =
if isNumber' ageValue then
Right mps
else
Left (IncorrectDataError ageValue)
where
ageValue = valueFromPairWithKey mps "age"
isNumber' str = all (True ==) (map isDigit str) && length str > 0
pairByKey mps key = head (filter (\(key',_) -> key' == key) mps)
valueFromPairWithKey mps key = snd $ pairByKey mps key
validatedData :: Either Error [(String,String)] -> Either Error [(String,String)]
validatedData (Left a) = Left a
validatedData (Right mps) =
if all (True ==) (map (\k -> containsPairWithKey mps k) keys) then
Right mps
else
Left IncompleteDataError
keys = ["firstName", "lastName", "age"]
containsPairWithKey :: [(String,String)] -> String -> Bool
containsPairWithKey mps key = length (filter (\(key',_) -> key' == key) mps) /= 0
mappedPairs :: Either Error [[String]] -> Either Error [(String,String)]
mappedPairs (Left a) = Left a
mappedPairs (Right vp) = Right $ map mapper vp
where
mapper vp = (vp!!0, vp!!1)
validatedPairs :: Either Error [[String]] -> Either Error [[String]]
validatedPairs (Left a) = Left a
validatedPairs (Right pairs) =
if all (True==) (map validatedPair pairs) then
Right pairs
else
Left ParsingError
parsedPairs :: Either Error [String] -> Either Error [[String]]
parsedPairs (Left a) = Left a
parsedPairs (Right p) = Right (map parsedPairAsList p)
parsedPairAsList :: String -> [String]
parsedPairAsList = splitOn " = "
validatedPair :: [String] -> Bool
validatedPair pairs = if length pairs == 2 && (head pairs) /= "" && (pairs !! 1) /= "" then True else False
parsedLines :: String -> [String]
parsedLines = splitOn "\n"
validatedLines :: [String] -> Either Error [String]
validatedLines lines =
if isEmpty lines then
Left ParsingError
else
Right lines
where
isEmpty strs = if length strs == 1 && head strs == "" then True else False
--(asPerson . validetedAge . validatedData . mappedPairs . validatedPairs . parsedPairs . validatedLines . parsedLines) "firstName = John\nlastName = Connor\nage = 1.2"
-- import Data.List.Split
-- import Data.Char
-- data Error = ParsingError | IncompleteDataError | IncorrectDataError String
-- data Person = Person { firstName :: String, lastName :: String, age :: Int }
-- parsePerson :: String -> Either Error Person
-- parsePerson str = if isValidStr str == False then
-- Left ParsingError
-- else if (hasAllFields fields pairs') == False then
-- Left IncompleteDataError
-- else if ageIsCorrect str == False then
-- Left (IncorrectDataError $ snd (valueOf "age" pairs'))
-- else
-- Right Person {
-- lastName = snd $ valueOf "age" pairs',
-- firstName = snd $ valueOf "firstName" pairs',
-- age = (read (snd $ valueOf "age" pairs')::Int)
-- }
-- where
-- pairs' = pairs str
-- fields = ["lastName", "firstName", "age"]
-- pairs str = map (\(key:value:[]) -> (key,value)) (filter isPair (map keyValues (fields str)))
-- isPair str = length str == 2
-- fields = splitOn "\n"
-- keyValues = splitOn " = "
-- isValidStr str = (length $ pairs str) > 0 && isValidFields str && (length (snd (age' str)) > 0)
-- valueOf key pairs = head (filter (\(key',_) -> key' == key) pairs)
-- isNumber' str = all (True ==) (map isDigit str) && length str > 0
-- hasAllFields fields pairs = all (True ==) (map (\f -> hasField f pairs) fields)
-- hasField field pairs = length (filter (\(key,_) -> key == field) pairs) > 0
-- age' str = valueOf "age" (pairs str)
-- ageIsCorrect str = isNumber' (snd (age' str))
-- isValidFields str = all (True==) (map (\f -> ((length (splitOn "=" f)) > 0) && ((length (splitOn " = " f)) > 0)) (fields str))
{-
sequence
words
lines
lookup
elem
data Error = ParsingError | IncompleteDataError | IncorrectDataError String
data Person = Person { firstName :: String, lastName :: String, age :: Int }
parseDictionary :: String -> Maybe [(String, String)]
parseDictionary = sequence . map (parseSet . words) . lines where
parseSet [n,"=",v] = Just (n,v)
parseSet _ = Nothing
parsePerson :: String -> Either Error Person
parsePerson s = case parseDictionary s of
Nothing -> Left ParsingError
Just d -> case lookup "firstName" d of
Nothing -> Left IncompleteDataError
Just fn -> case lookup "lastName" d of
Nothing -> Left IncompleteDataError
Just ln -> case lookup "age" d of
Nothing -> Left IncompleteDataError
Just ag -> case all (`elem` ['0'..'9']) ag of
False -> Left $ IncorrectDataError ag
True -> Right $ Person { firstName = fn, lastName = ln, age = read ag }
data Error = ParsingError | IncompleteDataError | IncorrectDataError String
data Person = Person { firstName :: String, lastName :: String, age :: Int }
parsePerson :: String -> Either Error Person
parsePerson = go . map words . lines where
go [["firstName","=",f],["lastName","=",l],["age","=",a]]
| all (flip elem ['0'..'9']) a =
Right $ Person { firstName = f, lastName = l, age = read a::Int }
| otherwise = Left $ IncorrectDataError a
go [a,b,c] = Left $ ParsingError
go _ = Left $ IncompleteDataError
import Data.Maybe
data Error = ParsingError | IncompleteDataError | IncorrectDataError String
data Person = Person { firstName :: String, lastName :: String, age :: Int }
parseSet :: String -> Either Error (String, String)
parseSet = go . words where
go [n,"=",v] = Right (n,v)
go _ = Left ParsingError
getField :: String -> [(String, String)] -> Either Error String
getField n m = maybe (Left IncompleteDataError) Right $ lookup n m
checkInt :: String -> Either Error Int
checkInt s | all (`elem` ['0'..'9']) s = Right $ read s
| otherwise = Left $ IncorrectDataError s
parsePerson :: String -> Either Error Person
parsePerson s = do
m <- sequence . map parseSet . lines $ s
n <- getField "firstName" m
l <- getField "lastName" m
a <- getField "age" m >>= checkInt
return Person { firstName = n, lastName = l, age = a }
-}