This is a derivation of Egison.
The purpose of this project is to make Egison a statically typed language.
This document is focused on the type system of Egison and written for developers of Egison.
You can test codes started with >
in the Typed Egison interpreter.
I assume you use Linux. Please use following commands to build Typed Egison.
git clone https://github.com/egison/typed-egison.git
stack init
stack solver
stack build
After build, you can start repl by
stack exec egison
You can use these commands in the interpreter
print-type-of
show the type of expressiondefine
define fucntions or constantsdefine-type-of
define type of functions or constantsdefine-ADT
define new ADT
The built-in types of Egison are
Char
, String
, Bool
, Integer
, Tuple
, Collection
, Fun
, Pattern
and Matcher
.
You can check the type of a expression using print-type-of
.
> (print-type-of c#a)
c#a :: Char
> (print-type-of "Hello")
"Hello" :: String
> (print-type-of #t)
#t :: Bool
> (print-type-of 42)
42 :: Integer
Tuple is a set of some types.
> (print-type-of [10 "hoge"])
[10 "hoge"] :: (Tuple Integer String)
Collection is used to represent a data which contains many same type datum.
> (print-type-of {10 20 40})
{10 20 40} :: (Collection Integer)
Fun is an abbreviation of a function of course. Functions in Egison are take a tuple and return a value.
> (print-type-of (lambda [$x] (b.+ x 10)))
(lambda [$x] (b.+ x 10)) :: (Fun (Tuple Integer) Integer)
This means (lambda [$x] (b.+ x 10))
takes a tuple of integer and return integer.
These two types are deeply related to match-all
syntax.
In short, match-all
looks like following.
(match-all "Data" "How to match" ["Pattern" "Result"])
"Collection of Result"
The following is an example of pattern matching in Egison.
> (match-all <Pair 2 5> (unorderd-pair integer) [<pair ,5 $x> x])
{2}
You don't have to understand details of <Pair 2 5>
, (unorderd-pair integer)
and <pair ,5 $x>
.
What I want to teach in this section is types of these parts. These types are
<Pair 2 5> :: PairII
(unordered-pair integer) :: Matcher PairII
<pair ,5 $x> :: Pattern PairII
PairII
is user-defined ADT. I will explain about ADT in a later section.
In this example, match-all
takes 3 arguments.
Their types are PairII
, (Matcher PairII)
, (Tuple (Pattern PairII) Integer)
respectively and return (Collection Integer)
.
More generally, match-all
takes 3 arguments, a
, (Matcher a)
, (Tuple (Pattern a) b)
and return (Collection b)
.
a
and b
are variables which refer some types like Integer
, Bool
or PairII
.
In rough words, match-all
has this type
(Fun (Tuple a (Matcher a) (Tuple (Pattern a) b)) (Collection b))
As you can see in the previous section, you can define algebraic data type in Egison.
define-ADT
is a syntax for defining ADT.
(define-ADT "Name of type" <"Name of type constructor" "type1" "type2" ...> <"Name of type constructor" ...>)
The name of type and names of type constructors must start from a capital case.
For example, PairII
is defined using following code.
(define-ADT PairII <Pair Integer Integer>)
After you execute above command, data constructor Pair
and pattern constructor pair
will be defined.
Names of pattern constructors are same with data constructors but pattern constructors are begun with small cases.
> (print-type-of Pair)
Pair :: (Fun (Tuple Integer Integer) PairII
> (print-type-of pair)
pair :: (Fun (Tuple (Pattern Integer) (Pattern Integer)) (Pattern PairII))
Please be careful. Pattern constructor has defined automatically.
When you define ADT, you must be careful not to conflict names.
You can use print-type-of
to check whether a name is used or not.
> (print-type-of unusedname)
Cannot decide the type of unusedname
Built-in functions (ex. b.+
, eq?
) are defined in Egison interpreter.
So the type checker cannot infer the type of these functions.
We must give the type declaration of these functions to type checker.
For such purpose, we can use define-type-of
.
When you write
(define-type-of $b.+ (Fun (Tnple Integer Integer) Integer))
type checker believe b.+
has (Fun (Tnple Integer Integer) Integer)
type.
For more examples, please check lib/core/type-primitive.egi
.
Type checker loads this file when it starts.
Caution
When you use ADT or type variables in define-type-of
, you must write like (TypeVar Pair)
.
For examples,
(define-type-of $eq? (Fun (Tuple (TypeVar a) (TypeVar a)) Bool))
(define-type-of somevalue (TypeVar PairII))
Theoretically, the type system of Egison is an extension of simply typed lambda calculus.
I extended simply typed lambda calculus with let polymorphism, Collection, Pattern, Matcher.
I made implicit conversion for Egison.
But it was not used now in the master branch.
You can check the implementation in hs-src/Language/Egison/ImplConv.hs.
Syntax for implicit conversion are absolute-implicit-conversion
and implicit-conversion
.
absolute-implicit-conversion
convert all possible variables absolutely.
This means that when you define absolute implicit conversion from String to Integer,
all values typed String is converted to Integer absolutely.
implicit-conversion
convert all possible variables so that the type check success.