2016.12.30 17:12
haskellowy koan
Wymyśliłem wczoraj taki haskellowy koan:
Oto prosta biblioteka do generowania zapytań eskuelowych - sprytna, bo kiedy budujemy nią wyrażenia, to pilnuje typów (na przykład żebyśmy pola tekstowego nie mnożyli przez liczbę):
data Table = Table String deriving Show
data Expression a = Expression String deriving Show
integerField :: String -> Expression Integer
integerField name = Expression name
integerLiteral :: Integer -> Expression Integer
integerLiteral value = Expression (show value)
(|+|) :: Expression Integer -> Expression Integer -> Expression Integer
(|-|) :: Expression Integer -> Expression Integer -> Expression Integer
(|*|) :: Expression Integer -> Expression Integer -> Expression Integer
(|/|) :: Expression Integer -> Expression Integer -> Expression Integer
(|+|) (Expression a) (Expression b) = Expression ("(" ++ a ++ " + " ++ b ++ ")")
(|-|) (Expression a) (Expression b) = Expression ("(" ++ a ++ " - " ++ b ++ ")")
(|*|) (Expression a) (Expression b) = Expression ("(" ++ a ++ " * " ++ b ++ ")")
(|/|) (Expression a) (Expression b) = Expression ("(" ++ a ++ " / " ++ b ++ ")")
stringField :: String -> Expression String
stringField name = Expression name
stringLiteral :: String -> Expression String
stringLiteral value = Expression (""" ++ value ++ """)
(|&|) :: Expression String -> Expression String -> Expression String
(|&|) (Expression a) (Expression b) = Expression (a ++ " & " ++ b)
data AnyExpression = IntegerExpression (Expression Integer) | StringExpression (Expression String)
expressionsToSql :: [AnyExpression] -> String
expressionsToSql [] = ""
expressionsToSql [IntegerExpression (Expression a)] = a
expressionsToSql [StringExpression (Expression a)] = a
expressionsToSql ((IntegerExpression (Expression a)):xs) = a ++ ", " ++ (expressionsToSql xs)
expressionsToSql ((StringExpression (Expression a)):xs) = a ++ ", " ++ (expressionsToSql xs)
toSql :: Table -> [AnyExpression] -> String
toSql (Table name) expressions = "select " ++ (expressionsToSql expressions) ++ " from " ++ name
Korzysta się z niej na przykład tak:
waga = integerField "waga"
wzrost = integerField "wzrost"
imie = stringField "imie"
nazwisko = stringField "nazwisko"
int_1337 = integerLiteral 1337
str_tralala = stringLiteral "tralala"
sql = toSql (Table "osoby") [IntegerExpression (waga |*| wzrost), IntegerExpression (waga |+| int_1337 |-| wzrost), StringExpression (imie |&| str_tralala |&| nazwisko)]
A teraz spróbuj napisać funkcję, która z rzeczy typu Expression Integer wyciąga ten integer. To znaczy napisz funkcję, która jest typu Expression Integer -> Integer.
Wymyśliłem to rozmyślając o haskellowym IO.
komentarze:
powrót na stronę główną
RSS