-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMaybe.hs
74 lines (50 loc) · 3.2 KB
/
Maybe.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
module Demo where
import Data.Char
-- import Prelude hiding (Maybe, Just, Nothing)
-- data Maybe a = Nothing | Just a deriving (Eq, Show)
-- instance Monad Maybe where
-- return = Just
-- (Just x) >>= k = k x
-- Nothing >>= _ = Nothing
{-
Рассмотрим язык арифметических выражений, которые состоят из чисел, скобок, операций сложения и вычитания. Конструкции данного языка можно представить следующим типом данных:
data Token = Number Int | Plus | Minus | LeftBrace | RightBrace
deriving (Eq, Show)
Реализуйте лексер арифметических выражений. Для начала реализуйте следующую функцию:
asToken :: String -> Maybe Token
Она проверяет, является ли переданная строка числом (используйте функцию isDigit из модуля Data.Char), знаком "+" или "-", открывающейся или закрывающейся скобкой. Если является, то она возвращает нужное значение обёрнутое в Just, в противном случае - Nothing:
GHCi> asToken "123"
Just (Number 123)
GHCi> asToken "abc"
Nothing
Далее, реализуйте функцию tokenize:
tokenize :: String -> Maybe [Token]
Функция принимает на вход строку и если каждое слово является корректным токеном, то она возвращает список этих токенов, завёрнутый в Just. В противном случае возвращается Nothing.
Функция должна разбивать входную строку на отдельные слова по пробелам (используйте библиотечную функцию words). Далее, полученный список строк должен быть свёрнут с использованием функции asToken и свойств монады Maybe:
GHCi> tokenize "1 + 2"
Just [Number 1,Plus,Number 2]
GHCi> tokenize "1 + ( 7 - 2 )"
Just [Number 1,Plus,LeftBrace,Number 7,Minus,Number 2,RightBrace]
GHCi> tokenize "1 + abc"
Nothing
Обратите внимание, что скобки отделяются пробелами от остальных выражений!
-}
data Token = Number Int | Plus | Minus | LeftBrace | RightBrace
deriving (Eq, Show)
-- Тип Token уже объявлен, его писать не нужно
asToken :: String -> Maybe Token
asToken t | "+" == t = Just Plus
| "-" == t = Just Minus
| "(" == t = Just LeftBrace
| ")" == t = Just RightBrace
| isNumber' t == True = Just (Number (read t :: Int))
| otherwise = Nothing
isNumber' str = all isDigit str
tokenize :: String -> Maybe [Token]
tokenize input = seq (map asToken (words input)) -- sequence
where
seq ms = foldr k (return []) ms
k m1 m2 = do
m1r <- m1
m2r <- m2
return (m1r:m2r)