Let's see some code!
The code samples I've provided here are subject to not be valid in any future implementation of this language. I'm still trying to figure everything out, and it's hard to go back and change everywhere where I stated something about this language. So, I don't think things will change much, but they will be left here to preserve a record of progress, so I can see what this language really started out as.
Literals
Here's what the literals look like:
Notice the types on the right of each literal expression. Num
,
Complex
, and Fractional
are all traits. The
type of these literals is similar to Haskell's typeclasses of the same
name. They represent the most general type that this literal can be. We'll
talk about traits in more detail in a later section. Bool
is a type with two constructors that take no arguments, True
and False
. Lists
and Sets
are
heterogenous, that is, they only hold objects of the same type. Lastly,
String
is not a trait like Num
and friends,
it is a proper class. It can be instantiated, and cannot be inherited from,
unlike traits. We'll talk about classes in more detail in a later section.
Binary Operators
Here are some basic operators:
Even though we haven't talked about idk-lang's type language yet, we
will use it here for a quick showcase of some of the features of this
language. The type of +
is Addable a => a ->
a -> a
. That is, +
takes in two objects of the
same type a
where the type a
must inherit the
trait Addable
. Since Num
and String
both inherit Addable
, the following expressions are both valid,
This shows one of the many advantages to using traits in a statically typed environment. It prevents the creation of over-engineered syntax to handle the “overloading” of operators on different types.
Boolean Operators
Lastly, we have the boolean operators:
The operator not
has type Bool -> Bool
.
The operators and
and or
both have type
Bool -> Bool -> Bool
. These work as expected,
and because of how strict this language is, there is never an implicit
cast or coercion to any type, so these functions only work on booleans.
Comparison Operators
We've seen some basic binary operators: + - / * ^
. A valid
type for all of these operators is Num a => a -> a ->
a
. That is, they take in two objects of the same type a
that implement the trait Num
, and return an object of type
a
that also implements that Num
. These are called
Numeric operators.
There is another group of operators called Comparison operators.
They all have type a -> a -> Bool
. That is, they take
in two objects, both of type a
and the and they return a
Bool
. Now, a
are type variables, they
represent any possible type. For example, the following operators are
Comparison operators
What is special about these operators is that they can be chained for greater expressive power. For example, this is a valid use of these operators,
These chains are equivalent to checking that every adjacent pair of
arguments to each operator returns
Partial(ly applied) operators
Another cool feature of operators is that they can be partially applied, esentially equivalent to Haskell's operator sections except without any iterated section support. For example,
These can be really expressive when using maps or filters.
The next section is on forms,
where we'll talk about assignment, if
expressions, and
where
expressions.