Idris for Pedestrians
Alexander Tchitchigin
Typeable.io
Big picture
Idris characteristics
- Research language
- Changes rapidly
- Not always backwards-compatible
- Parts lack documentation
- Not for production
- Basic runtime
- Bugs
- Self-disruptive :D
- Blodwen
Idris features
- Pure functional language
- Totality-checker
- Interfaces
- MONADS
- Dependent types
- Types depend on values
- Π-, Σ- and equality types
- Proofs
- Manual
- Elaborator Reflection
Functional programming
data MyList : (a : Type) -> Type where
Nil : MyList a
Cons : a -> MyList a -> MyList a
myAppend : MyList a -> MyList a -> MyList a
myAppend Nil ys = ys
myAppend (Cons x xs) ys = Cons x (myAppend xs ys)Actual definitions
data List a = [] | a :: (List a)
append : List a -> List a -> List a
append [] ys = ys
append (x :: xs) ys = x :: (append xs ys)Dependent types
data Vect : (n : Nat) -> (a : Type) -> Type where
Nil : Vect 0 a
Cons : a -> Vect n a -> Vect (S n) a
vAppend : Vect n a -> Vect m a -> Vect (n+m) a
vAppend Nil ys = ys
vAppend (Cons x xs) ys = Cons x (vAppend xs ys)More dependent types
myZip : List a -> List b -> List (a, b)
myZip [] _ = []
myZip _ [] = []
myZip (x :: xs) (y :: ys) = (x, y) :: myZip xs ysvZip : Vect n a -> Vect n b -> Vect n (a, b)
vZip [] [] = []
vZip (Cons x y) (Cons z w) = Cons (x, z) (vZip y w)Step by step
vZip : Vect n a -> Vect n b -> Vect n (a, b)
vZip [] [] = []
vZip (Cons x y) (Cons z w) = Cons (x, z) (vZip y w)vZip : Vect n a -> Vect n b -> Vect n (a, b)
vZip [] [] = []
vZip (Cons x y) (Cons z w) = ?n_1vZip : Vect n a -> Vect n b -> Vect n (a, b)
vZip [] [] = ?n_1
vZip (Cons x y) ys = ?n_2vZip : Vect n a -> Vect n b -> Vect n (a, b)
vZip [] ys = ?n_1
vZip (Cons x y) ys = ?n_2vZip : Vect n a -> Vect n b -> Vect n (a, b)
vZip xs ys = ?nTricky case
vFilter : (a -> Bool) -> Vect n a -> (m : Nat ** Vect m a)
vFilter pred [] = (0 ** [])
vFilter pred (Cons x xs) = if pred x
then let (n ** xs') = vFilter pred xs
in (S n ** (Cons x xs'))
else vFilter pred xsmyFilter : (a -> Bool) -> List a -> List a
myFilter pred [] = []
myFilter pred (x :: xs) = if pred x
then x :: myFilter pred xs
else myFilter pred xsData store
$ ./datastore
Command: new String Int
OK.
Command: new Int String
OK.
Command: add 2 "two"
ID 0.
Command: add 3 "3"
ID 1.
Command: add 4 "1111"
ID 2.
Command: get 1
3, "3"
Command: get 2
4, "1111"
Command: get 0
2, "two"
Command: quitData store
module Main
import Data.Vect
infixr 5 .+.
data Schema = SInt | SString | (.+.) Schema Schema
SchemaType : Schema -> Type
SchemaType SInt = Int
SchemaType SString = String
SchemaType (x .+. y) = (SchemaType x, SchemaType y)
display : SchemaType schema -> String
display {schema = SInt} item = show item
display {schema = SString} item = show item
display {schema = (x .+. y)} (a, b) = display a ++ ", " ++ display bData store
record DataStore where
constructor MkData
schema : Schema
size : Nat
items : Vect size (SchemaType schema)
-- Returns new store with given element added as the last one
addToStore : (store : DataStore) -> SchemaType (schema store) -> DataStore
addToStore (MkData schema size items) newItem = MkData schema _ (addToData items)
where
addToData : Vect n (SchemaType schema) -> Vect (S n) (SchemaType schema)
addToData [] = [newItem]
addToData (x :: xs) = x :: addToData xs
-- Return an item by index if index is within bounds
-- `Maybe (String, DataStore)` to match the type of a caller
getEntry : (pos : Integer) -> (store : DataStore) -> Maybe (String, DataStore)
getEntry pos store = case integerToFin pos (size store) of
Nothing => Just ("Out of range.\n", store)
Just id => Just (display (index id (items store)) ++ "\n", store)Data store
data Command : Schema -> Type where
New : (newSchema : Schema) -> Command schema
Add : SchemaType schema -> Command schema
Get : Integer -> Command schema
Quit : Command schema
parseCommand : (schema : Schema) -> String -> String -> Maybe (Command schema)
parseCommand schema "add" rest = case parseBySchema schema rest of
Just val => Just (Add val)
Nothing => Nothing
parseCommand schema "get" val = if all isDigit (unpack val)
then Just (Get (cast val))
else Nothing
parseCommand schema "quit" "" = Just Quit
parseCommand schema "new" rest = case parseSchema (words rest) of
Nothing => Nothing
Just newSchema => Just (New newSchema)
parseCommand _ _ _ = Nothing
parse : (schema : Schema) -> String -> Maybe (Command schema)
parse schema input = let (cmd, args) = span (/= ' ') input in
parseCommand schema cmd (ltrim args)Data store
parsePrefix : (schema : Schema) -> String -> Maybe (SchemaType schema, String)
parsePrefix SInt input = case span isDigit input of
("", rest) => Nothing
(num, rest) => Just (cast num, ltrim rest)
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 (x .+. y) input = case parsePrefix x input of
Nothing => Nothing
Just (val1, input') => case parsePrefix y input' of
Nothing => Nothing
Just (val2, input'') => Just ((val1, val2), ltrim input'')
parseBySchema : (schema : Schema) -> String -> Maybe (SchemaType schema)
parseBySchema schema input = case parsePrefix schema input of
Just (res, "") => Just res -- there should be no leftovers
Just _ => Nothing
Nothing => NothingData store
parseSchema : List String -> Maybe Schema
parseSchema ("String" :: xs) = if isNil xs
then Just SString
else case parseSchema xs of
Nothing => Nothing
Just schema => Just (SString .+. schema)
parseSchema ("Int" :: xs) = if isNil xs
then Just SInt
else case parseSchema xs of
Nothing => Nothing
Just schema => Just (SInt .+. schema)
parseSchema _ = Nothing
setSchema : DataStore -> Schema -> Maybe DataStore
setSchema store schema = case size store of
Z => Just (MkData schema _ [])
_ => Nothing -- do not change schema when the store is not emptyData store
processInput : DataStore -> String -> Maybe (String, DataStore)
processInput store input = case parse (schema store) input of
Nothing => Just ("Invalid command.\n", store)
Just (New schema') => case setSchema store schema' of
Nothing => Just ("Can't change schema.\n", store)
Just store' => Just ("OK.\n", store')
Just (Add item) =>
Just ("ID " ++ show (size store) ++ ".\n", addToStore store item)
Just (Get pos) => getEntry pos store
Just Quit => Nothing
main : IO ()
main = replWith (MkData SString _ []) "Command: " processInputWhat else?
- Interfaces and Implementations
- State and State Machines
- Codata and Streams
- Effects
- Linear Types
- Theorems and Proofs
- Packages, FFI, interactive mode, etc.
References
Thanks for your attention!
Questions please. :)
Idris for Pedestrians
By Alexander Letov
Idris for Pedestrians
Birdeye's view on Idris.
- 104