[ToC]
Hamler is strongly typed, and has a powerful static type system. Let's start with some simple examples.
Boolean
true :: Boolean
false :: BooleanNumbers
Hamler has Integer and Float, and since they have different types so they can't be mixed.
--Integer
1 :: Integer
--Float
0.1 :: FloatAtoms
Atom is probably more familiar to Erlang user. It is a literal, a constant with a name starting with : .
:hello
:world
Strings
In Hamler String is just a list of Char
"Hello World" :: String -- ['H','e','l','l','o',',','W','o','r','l','d']Binaries
This is the very unique datatype that exists in Erlang. Binary contains the same information as ByteString and if you are not very familiar with binaries, this link should be helpful for some intuition.
<<1,2,3:8,4:16,5,"abcdefg">> :: Binary| Operator | Meaning | Operator | Meaning | |
|---|---|---|---|---|
| + | Numeric addition | == | Equality check | |
| - | Numeric subtraction | < | Less than | |
| * | Numeric multiplication | <= | Less than or equal | |
| / | Numeric division (div) | > | Greater than | |
| % | Remainder | >= | Greater than or equal | |
| && | Boolean AND | || | Boolean OR |
When we define a new function, we can give it a type signature. For example double is a function takes an Integer and gives an Integer doubled as output.
double :: Integer -> Integer
double x = x * 2Lambda Expression
There are also lambda expressions in Hamler, here is an example of how we rewrite double.
double' :: Integer -> Integer
double' = \x -> 2 * xIt becomes really handy when we need to make an anonymous function.
Currying
--Curry
--This is uncurried (+)
add :: (Integer, Integer) -> Integer
add (x, y) = x + y
--This is curried (+)
plus :: Integer -> Integer -> Integer
plus x y = x + yPartial Application
-- plus :: Integer -> (Integer -> Integer) This is one of the example of higher order functions
>:t plus 2
plus 2:: Integer -> Integer
>let plusTwo = plus2
>plusTwo 3
5They are also known as polymorphic types.
> :type id
id :: forall a. a -> aThe key word forall indicates that id is univerally quantified, meaning that id can be applied to any type.
> id 1
1A more complicated example is flip. flip is also a higher-order function, which will be explained in a later chapter.
> :type flip
forall a b c. (a -> b -> c) - > b -> a -> cLike a lot of ML based languages, Hamler is indentation sensitive. Any declaration in the same block should have the same level of indentation. In the case of a declaration spans more than one line, the other lines have to be intended past the first line.
flip x f = f
x -- NOT OKAY, Hamler will see x as a seperate declaration
flip f x = f
x -- OKAY, but not recommendedLet and Where Bindings
Keywords such as let and where introduce a new block, where further indentation is needed.
distance x y = sqrt z
where
z = x' + y'
x' = x * x
y' = y * yType synonym can be used to simplify a long type name to make the code more readable.
>:i String
type String = [Char]Or you can define you own synonym name or a record.
type Name = String
type Person =
{ firstName :: Name
, secondName :: Name
}
{-
This is syntax sugared
"type Person = Record (FirstName :: Name , SecondName :: Name)"
-}Fields can be accessed by .
leader :: Person
leader = {firstName = "John", lastName = "Portsman"}
>leader.firstName
"John"This is how we update a record.
newLeader :: Person
newLeader = leader{firstName = "James"}
>newLeader.firstName
"James"a = { name = "yang"
, position =
{ streetNumber = 232
, location = { x = 12.223
, y = 45.9
}
}
}
b = a{position.location.x = 10.003}
> a.position.location.x
12.223
> b.position.location.x
10.003
a = { name = "yang"
, pos ={ x = 10
, y = 20
, info = { s = "val"
, v = 45.9
}
}
}
b = a{pos.info.s = "newVal"}