The book's Chapter6's datastore:
module Main
import Data.Vect
infixr 5 .+.
data Schema = SString | SInt | (.+.) Schema Schema
SchemaType : Schema -> Type
SchemaType SString = String
SchemaType SInt = Int
SchemaType (x .+. y) = (SchemaType x, SchemaType y)
record DataStore where
constructor MkData
schema : Schema
size : Nat
items : Vect size (SchemaType schema)
addToStore : (store : DataStore) -> SchemaType (schema store) -> DataStore
addToStore (MkData schema size store) newitem = MkData schema _ (addToData store)
where
addToData : Vect oldsize (SchemaType schema) -> Vect (S oldsize) (SchemaType schema)
addToData [] = [newitem]
addToData (x :: xs) = x :: addToData xs
setSchema : (store : DataStore) -> Schema -> Maybe DataStore
setSchema store schema = case size store of
Z => Just (MkData schema _ [])
S k => Nothing
data Command : Schema -> Type where
SetSchema : Schema -> Command schema
Add : SchemaType schema -> Command schema
Get : Integer -> Command schema
Quit : Command schema
parsePrefix : (schema : Schema) -> String -> Maybe (SchemaType schema, String)
parsePrefix SString input = getQuoted (unpack input)
where
getQuoted : List Char -> Maybe (String, String)
getQuoted ('"' :: xs)
= case span (/= '"') xs of
(quoted, '"' :: rest) => Just (pack quoted, ltrim (pack rest))
_ => Nothing
getQuoted _ = Nothing
parsePrefix SInt input = case span isDigit input of
("", rest) => Nothing
(num, rest) => Just (cast num, ltrim rest)
parsePrefix (schemal .+. schemar) input
= case parsePrefix schemal input of
Nothing => Nothing
Just (l_val, input') =>
case parsePrefix schemar input' of
Nothing => Nothing
Just (r_val, input'') => Just ((l_val, r_val), input'')
parseBySchema : (schema : Schema) -> String -> Maybe (SchemaType schema)
parseBySchema schema x = case parsePrefix schema x of
Nothing => Nothing
Just (res, "") => Just res
Just _ => Nothing
parseSchema : List String -> Maybe Schema
parseSchema ("String" :: xs)
= case xs of
[] => Just SString
_ => case parseSchema xs of
Nothing => Nothing
Just xs_sch => Just (SString .+. xs_sch)
parseSchema ("Int" :: xs)
= case xs of
[] => Just SInt
_ => case parseSchema xs of
Nothing => Nothing
Just xs_sch => Just (SInt .+. xs_sch)
parseSchema _ = Nothing
parseCommand : (schema : Schema) -> String -> String -> Maybe (Command schema)
parseCommand schema "add" rest = case parseBySchema schema rest of
Nothing => Nothing
Just restok => Just (Add restok)
parseCommand schema "get" val = case all isDigit (unpack val) of
False => Nothing
True => Just (Get (cast val))
parseCommand schema "quit" "" = Just Quit
parseCommand schema "schema" rest
= case parseSchema (words rest) of
Nothing => Nothing
Just schemaok => Just (SetSchema schemaok)
parseCommand _ _ _ = Nothing
parse : (schema : Schema) -> (input : String) -> Maybe (Command schema)
parse schema input = case span (/= ' ') input of
(cmd, args) => parseCommand schema cmd (ltrim args)
display : SchemaType schema -> String
display {schema = SString} item = show item
display {schema = SInt} item = show item
display {schema = (y .+. z)} (iteml, itemr) = display iteml ++ ", " ++
display itemr
getEntry : (pos : Integer) -> (store : DataStore) ->
Maybe (String, DataStore)
getEntry pos store
= let store_items = items store in
case integerToFin pos (size store) of
Nothing => Just ("Out of range\n", store)
Just id => Just (display (index id (items store)) ++ "\n", store)
processInput : DataStore -> String -> Maybe (String, DataStore)
processInput store input
= case parse (schema store) input of
Nothing => Just ("Invalid command\n", store)
Just (Add item) =>
Just ("ID " ++ show (size store) ++ "\n", addToStore store item)
Just (SetSchema schema') =>
case setSchema store schema' of
Nothing => Just ("Can't update schema when entries in store\n", store)
Just store' => Just ("OK\n", store')
Just (Get pos) => getEntry pos store
Just Quit => Nothing
main : IO ()
main = replWith (MkData (SString .+. SString .+. SInt) _ []) "Command: " processInput
it can define scheme of a "database" with String and Int in runtime:
Command: schema String String Int OK Command: add "Rain Dogs" "Tom Waits" 1985 ID 0 Command: add "Fog on the Tyne" "Lindisfarne" 1971 ID 1 Command: get 1 "Fog on the Tyne", "Lindisfarne", 1971 Command: quit
I want to know if any dynamic language like ruby or python can do the same thing?In the static language,the scheme must be defined before the compile.
Thanks!
The purpose of a static type system is to reject ill-typed programs. In other words, a static type system prevents you from writing programs.
So, if you can write a program in a language with a static type system, then you can also write that same program in a language without a static type system.
Note that this is an extremely simplified explanation. I am well aware of the power of static type systems, and I love to use them. However, when it comes down to it, a static type system never enables you to write a program you couldn't otherwise write, it only prevents you from writing programs that are not well-typed.
This can be alleviated by something like F#'s Type Providers. Type Providers are code that runs during the compilation process and can generate type information that is not statically available in the program source text.
For example, there is a
SQLProviderwhich can connect to a SQL database, read out its schema, and generate F# types from the schema.But, of course, all of this still happens at compile time. The generated types will be the ones from the time you compiled the program, not when you actually connect to the database, and if the database schema changes, you have to re-run the type provider to generate new types.