├── book ├── ERTS.md ├── Behaviours.md ├── DataTypes.md ├── Databases.md ├── Lambda.md ├── Sockets.md ├── TypeClass.md ├── Control │ └── Monad.md ├── DataTypes │ ├── Maps.md │ ├── Binaries.md │ ├── Records.md │ ├── AlgebraicDataTypes.md │ ├── Lists.md │ └── BasicTypes.md ├── Databases │ ├── ETS.md │ └── Mnesia.md ├── ERTS │ └── Atomics.md ├── Expressions.md ├── Installation.md ├── Introduction.md ├── PatternMatch.md ├── Sockets │ ├── CoAP.md │ ├── Inet.md │ ├── MQTT.md │ ├── QUIC.md │ ├── TCP.md │ └── UDP.md ├── Distribution │ └── RPC.md ├── Expressions │ ├── CaseOf.md │ ├── Guards.md │ ├── IfElse.md │ ├── LetIn.md │ ├── Where.md │ └── Operators.md ├── REPL.md ├── Behaviours │ ├── GenEvent.md │ ├── GenServer.md │ ├── GenStatem.md │ └── Supervisor.md ├── README ├── Distribution.md ├── Exceptions.md ├── Process.md ├── Modules.md ├── Types.md ├── SendRecv.md ├── Recursion.md ├── ListComprehensions.md └── Functions.md ├── design ├── README └── ReservedWords.md ├── courses └── README.md ├── .gitmodules ├── guides ├── 12_NodeAndDistributedErlang.md ├── 15_DifferencesFromPurescript.md ├── 06_TypeClasses.md ├── 07_ApplicativeAndMonad.md ├── 14_DifferencesFromHaskell.md ├── 08_ForeignFunctionInterface.md ├── 05_HigherOrderFunctionsAndRecursions.md ├── 02_QuickStart.md ├── 01_WhyHamler.md ├── 10_MessagePassingConcurrency.md ├── 04_MoreTypesandPatternMatching.md ├── 13_DifferencesFromErlang.md ├── 03_BasicTypesFunctionsAndOperators.md ├── 09_DataTypesMapping.md └── 11_OTPBehaviours.md ├── FAQ.md ├── LICENSE ├── README.md └── Cheatsheet.md /book/ERTS.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Behaviours.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/DataTypes.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Databases.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Lambda.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Sockets.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/TypeClass.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Control/Monad.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/DataTypes/Maps.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Databases/ETS.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/ERTS/Atomics.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Expressions.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Installation.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Introduction.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/PatternMatch.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Sockets/CoAP.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Sockets/Inet.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Sockets/MQTT.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Sockets/QUIC.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Sockets/TCP.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Sockets/UDP.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/DataTypes/Binaries.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/DataTypes/Records.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Databases/Mnesia.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Distribution/RPC.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Expressions/CaseOf.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Expressions/Guards.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Expressions/IfElse.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Expressions/LetIn.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Expressions/Where.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/Expressions/Operators.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/DataTypes/AlgebraicDataTypes.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/REPL.md: -------------------------------------------------------------------------------- 1 | ## REPL 2 | 3 | 4 | -------------------------------------------------------------------------------- /book/Behaviours/GenEvent.md: -------------------------------------------------------------------------------- 1 | ## GenEvent Behaviour 2 | -------------------------------------------------------------------------------- /book/README: -------------------------------------------------------------------------------- 1 | <> 2 | -------------------------------------------------------------------------------- /book/Distribution.md: -------------------------------------------------------------------------------- 1 | ## Distribution 2 | 3 | ### Node 4 | -------------------------------------------------------------------------------- /book/Behaviours/GenServer.md: -------------------------------------------------------------------------------- 1 | 2 | ## GenServer Behaviour 3 | -------------------------------------------------------------------------------- /book/Behaviours/GenStatem.md: -------------------------------------------------------------------------------- 1 | 2 | ## GenStatem Behaviour 3 | -------------------------------------------------------------------------------- /book/Behaviours/Supervisor.md: -------------------------------------------------------------------------------- 1 | 2 | ## Supervisor Behaviour 3 | -------------------------------------------------------------------------------- /design/README: -------------------------------------------------------------------------------- 1 | The design of hamler programming language 2 | -------------------------------------------------------------------------------- /courses/README.md: -------------------------------------------------------------------------------- 1 | # Hamler for Erlang Programmer 2 | [ppt](https://slides.com/shangdi/deck) 3 | -------------------------------------------------------------------------------- /book/Exceptions.md: -------------------------------------------------------------------------------- 1 | ## Exceptions 2 | 3 | ### throw 4 | 5 | ### error 6 | 7 | ### try ... catch 8 | -------------------------------------------------------------------------------- /book/Process.md: -------------------------------------------------------------------------------- 1 | ## Process 2 | 3 | ### Spawn a process 4 | 5 | ### Link 6 | 7 | ### Monitor 8 | 9 | ### Exit 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "courses/hamlerDemo"] 2 | path = courses/hamlerDemo 3 | url = https://github.com/EMQ-YangM/hamlerDemo.git 4 | -------------------------------------------------------------------------------- /book/Modules.md: -------------------------------------------------------------------------------- 1 | ## Modules 2 | 3 | ### Module Declaration 4 | 5 | ### Export 6 | 7 | ### Import 8 | 9 | ### Import as 10 | -------------------------------------------------------------------------------- /book/Types.md: -------------------------------------------------------------------------------- 1 | ## Type Declarations 2 | 3 | ### type Declarations 4 | 5 | ### newtype Declarations 6 | 7 | ### data Declarations 8 | -------------------------------------------------------------------------------- /book/SendRecv.md: -------------------------------------------------------------------------------- 1 | ## Send and Receive 2 | 3 | ### Send a message 4 | 5 | ### Receive 6 | 7 | ### Receive after 8 | 9 | ### Select Receive 10 | 11 | -------------------------------------------------------------------------------- /book/DataTypes/Lists.md: -------------------------------------------------------------------------------- 1 | ## Lists 2 | 3 | ### Map 4 | 5 | ### Filter 6 | 7 | ### Fold 8 | 9 | ### Reverse 10 | 11 | ### Zip 12 | 13 | ### Exercises 14 | -------------------------------------------------------------------------------- /book/Recursion.md: -------------------------------------------------------------------------------- 1 | ## Recursion 2 | 3 | ### Introduction 4 | 5 | ### Recursive Functions 6 | 7 | ### Tail Recursive Functions 8 | 9 | ### Recursive Data Types 10 | 11 | ### Exercises 12 | -------------------------------------------------------------------------------- /book/DataTypes/BasicTypes.md: -------------------------------------------------------------------------------- 1 | ## Basic Types 2 | 3 | ### Atom 4 | ### Boolean 5 | ### Char 6 | ### Integer 7 | ### Float 8 | ### String 9 | ### Tuple 10 | ### List 11 | ### Map 12 | ### Record 13 | ### Binary 14 | -------------------------------------------------------------------------------- /book/ListComprehensions.md: -------------------------------------------------------------------------------- 1 | ## List Comprehensions 2 | 3 | ### Overview 4 | 5 | [x+2 | x <- [1..10]] 6 | 7 | ### Generators 8 | 9 | ### Dependent Generators 10 | 11 | ### Guards 12 | 13 | ### Expression 14 | 15 | ### Exercises 16 | -------------------------------------------------------------------------------- /design/ReservedWords.md: -------------------------------------------------------------------------------- 1 | ## Reserved Words 2 | 3 | ```haskell 4 | myAtom ado as case class data derive do else false forall forallu foreign hiding import if in infix infixl infixr instance kind let module newtype of then true type where 5 | ``` 6 | -------------------------------------------------------------------------------- /book/Functions.md: -------------------------------------------------------------------------------- 1 | ## Functions 2 | 3 | ### Define Functions 4 | 5 | ### Function Application 6 | 7 | ### Polymorphic Functions 8 | 9 | ### Pattern Matching 10 | 11 | ### Guards 12 | 13 | ### Recursion 14 | 15 | ### Lambda and Anonymous functions 16 | 17 | ### Closure 18 | 19 | ### Higher-Order Functions 20 | 21 | ### Curring 22 | 23 | ### Partial Application 24 | 25 | ### Composition and Pipeline 26 | 27 | ### inflix Operator 28 | 29 | ### Exercises 30 | -------------------------------------------------------------------------------- /guides/12_NodeAndDistributedErlang.md: -------------------------------------------------------------------------------- 1 | # Node and Distributed Erlang 2 | 3 | [ToC] 4 | 5 | ## Distributed Erlang/OTP 6 | 7 | Hamler is compiled to Erlang/OTP, which is a concurrent, fault-tolerant, distributed programming platform. A distributed Erlang/OTP system consists of a number of Erlang runtime systems called `node`. Nodes are connected with TCP/IP sockets and communicate by message passing. 8 | 9 | ![DistributedNodes](https://www.hamler-lang.org/images/distributed-nodes.png) 10 | 11 | ## Connect Nodes 12 | 13 | An Erlang runtime system -- `node` is identified by a unique name like an email address. Erlang nodes communicate with each other via these names. 14 | 15 | Start Erlang `epmd` for registering node name first: 16 | 17 | ```shell 18 | epmd -daemon 19 | ``` 20 | 21 | Start `n1@127.0.0.1` on a `Hamler REPL` console: 22 | 23 | ```shell 24 | hamler repl 25 | > import Control.Distributed.Node 26 | > import Control.Distributed.NetKernel 27 | > start :"n1@127.0.0.1" 28 | ``` 29 | 30 | Start `n2@127.0.0.1` on another `Hamler REPL` console, then connect to the `n1@127.0.0.1` node: 31 | 32 | ```shell 33 | hamler repl 34 | > import Control.Distributed.Node 35 | > import Control.Distributed.NetKernel 36 | > start :"n2@127.0.0.1" 37 | > connectNode :"n1@127.0.0.1" 38 | true 39 | > nodes 40 | ['n1@127.0.0.1'] 41 | ``` 42 | 43 | ## RPC 44 | 45 | -- TODO: ... 46 | 47 | -------------------------------------------------------------------------------- /guides/15_DifferencesFromPurescript.md: -------------------------------------------------------------------------------- 1 | # Main differences between Hamler and Purecript 2 | 3 | Hamler added syntaxes which are more familiar to Erlang programmers. 4 | 5 | ### Binary 6 | 7 | Hamler support Binary 8 | 9 | ```haskell 10 | getA :: Binary -> Maybe Integer 11 | getA << a:24:Big-Integer , b:4:Binary-Little , c:3:Binary >> = Just a 12 | getA _ = Nothing 13 | ``` 14 | 15 | ### Map 16 | 17 | Map in Hamler is more similar to Erlang 18 | 19 | ```haskell 20 | getID :: Map String Integer -> Maybe Integer 21 | getID #{ "Wang":= x, "Thomas" := y, "Leeming" := z } = Just x 22 | getID _ = Nothing 23 | ``` 24 | 25 | ### Atom 26 | 27 | We have atoms and allow pattern match on atom. It is now one of the primitive type in Hamler. 28 | 29 | ``` 30 | :hello 31 | :world 32 | :hello_World123 33 | ``` 34 | 35 | ### String 36 | 37 | In PureScript, `String` is one of the primitive type. However, in Hamler String is `[Char]` a list of `Char`s. 38 | 39 | ### Tuple 40 | 41 | Tuple can be represented with `(a,b)`. Ant they can be pattern matched and are one of the primitive type. 42 | 43 | ### List 44 | 45 | We have use List instead of Array. 46 | 47 | ``` 48 | [1..10] --[1,2,3,4,5,6,7,8,9,10] 49 | [(x,y)| x <- [1..10], y <- [1..10]]] --[(1,1),(1,2)... 50 | [a,b,c,d] 51 | [a|[b,c,d]] 52 | [x|xs] 53 | [1|[2|[3|[4|[5,6,7]]]]] 54 | ``` 55 | 56 | 57 | 58 | ## Other syntax changes 59 | 60 | While declaring class and instances we use Haskell's syntax. 61 | 62 | ```haskell 63 | class Applicative m => Monad m 64 | 65 | instance Monad List where 66 | ``` 67 | 68 | -------------------------------------------------------------------------------- /guides/06_TypeClasses.md: -------------------------------------------------------------------------------- 1 | # Type Class 2 | 3 | [ToC] 4 | 5 | ## Introduction 6 | 7 | A type class defines some types related by their operations. This is saying that typeclasses are usually defined in terms of those operations, and these operations group those types together. 8 | 9 | For example, we can put all types that can be converted to a `String` in the same type class called `Show` . 10 | 11 | We can introduce this `Show` type class by: 12 | 13 | ```haskell 14 | class Show a where 15 | show :: a -> String 16 | ``` 17 | 18 | Then we can give an instance to the type class. 19 | 20 | ```haskell 21 | instance Show String where 22 | show s = s 23 | 24 | instance Show Boolean where 25 | show true = "true" 26 | show false = "false" 27 | ``` 28 | 29 | ## Functor 30 | 31 | We have seen how map is defined for `[]`, and we can also map on other types. We call these types `Functor` if they can be `map`ped and can satistify the `Functor` law at the same time. 32 | 33 | Functor laws: `map id = id | map (compose g f) = map g . map f ` 34 | 35 | ```haskell 36 | class Functor f where 37 | map :: forall a b. (a -> b) -> f a -> f b 38 | 39 | instance Functor Maybe where 40 | map f (Just x) = Just (f x) 41 | map f Nothing = Nothing 42 | ``` 43 | 44 | ## Common type classes 45 | 46 | ```haskell 47 | class Eq a where 48 | eq :: a -> a -> Boolean 49 | 50 | -- data Ordering = LT | GT | EQ 51 | class Eq a => Ord a where 52 | compare :: a -> a -> Ordering 53 | 54 | class Foldable f where 55 | foldl :: forall a b. (b -> a -> b) -> b -> f a -> b 56 | foldr :: forall a b. (a -> b -> b) -> b -> f a -> b 57 | foldMap :: forall a m. Monoid m => (a -> m) -> f a -> m 58 | ``` 59 | -------------------------------------------------------------------------------- /guides/07_ApplicativeAndMonad.md: -------------------------------------------------------------------------------- 1 | # Applicative and Monad 2 | 3 | [ToC] 4 | 5 | In this chapter, we are going to look at two very important type class, Applicative Functor and Monad. 6 | 7 | ## Functor 8 | 9 | TODO:... 10 | 11 | ## Applicative 12 | 13 | Let's start with how the Applicative class is defined. From the definition, we can see that Applicatives are Functors with two more operations, which is pure and apply. `pure` wraps some value to make an applicative functor. `apply` is a bit more complicated. 14 | 15 | Let's just look at its type, does that ring a bell? Yeah, it looks like map except we have functions wrapped inside an applicative functor. What `apply` does is extract the function(s) from the functor and map them to the `f a` . 16 | 17 | ```haskell 18 | class Functor f => Applicative f where 19 | pure :: forall a. a -> f a 20 | apply :: forall a b. f (a -> b) -> f a -> f b 21 | 22 | infixl 4 apply as <*> 23 | ``` 24 | 25 | Here are some examples of intances of `Applicatve` 26 | 27 | ```haskell 28 | instance Applicative Maybe where 29 | pure = Just 30 | Nothing <*> mb = Nothing 31 | (Just f) <*> mb = map f mb 32 | ``` 33 | 34 | Let's have a closer look at instance `Applicative []` , we can see that every `f` in the list will get applied to all the elements in the list. So with `(+) <$> [1,2] <*> [3,4,5]`, we will have a non-deterministic computation on `(+)`. 35 | 36 | ## Monad 37 | 38 | ```haskell 39 | class Applicative m => Monad m where 40 | bind :: forall a b. m a -> (a -> m b) -> m b 41 | return :: forall a. a -> m a 42 | ``` 43 | 44 | ## `lift`ing 45 | 46 | ```Haskell 47 | liftA1 :: forall a b f. Applicative f => (a -> b) -> f a -> f b 48 | liftA1 f a = pure f <*> a 49 | 50 | liftA2 :: forall a b c f. Applicative f => (a -> b -> c) -> f a -> f b -> f c 51 | liftA2 f a b = pure f <*> a <*> b 52 | 53 | liftM1 :: forall a b m. Monad m => (a -> b) -> m a -> m b 54 | liftM1 f ma = do 55 | a <- ma 56 | return (f a) 57 | 58 | liftM2 :: forall a b c m. Monad m => (a -> b -> c) -> m a -> m b -> m c 59 | liftM2 f ma mb = do 60 | a <- ma 61 | b <- mb 62 | return (f a b) 63 | ``` 64 | -------------------------------------------------------------------------------- /guides/14_DifferencesFromHaskell.md: -------------------------------------------------------------------------------- 1 | # Differences between Hamler and Haskell 2 | 3 | **(Since the compiler is forked from purescript's, we have inherited some differences between Purescript and Haskell)** 4 | 5 | ## Module Imports / Exports 6 | 7 | Type classes in modules must be specifically imported using the class keyword. 8 | 9 | ```haskell 10 | module B where 11 | 12 | import A (class Fab) 13 | ``` 14 | 15 | See: [Ref](https://github.com/purescript/documentation/blob/master/language/Differences-from-Haskell.md) 16 | 17 | ## Types 18 | 19 | We use explicit `forall`. 20 | 21 | ```haskell 22 | id :: forall a. a -> a 23 | ``` 24 | 25 | ## Float 26 | 27 | There is no `Double` in Hamler, just `Float` 28 | 29 | ## List 30 | 31 | ```haskell 32 | {- hamler <–> haskell 33 | [] [] 34 | [1,2,3] [1,2,3] 35 | [1|[2|[3|[]]]] 1:2:3:[] 36 | 37 | Only in hamler [1,2,3|[2,3|[1,2]]] --[1,2,3,2,3,1,2] 38 | -} 39 | ``` 40 | 41 | ## Records 42 | 43 | ```haskell 44 | data Person = Person { name :: String , age :: Integer } 45 | p = Person {name = "alice", age = 30} --create a new record 46 | n = p.name -- access record field 47 | a = p.age 48 | np = p {age = 31} --new record 49 | ``` 50 | 51 | ## Deriving 52 | 53 | Same with PureScript, Hamler doesn't have `deriving` functionality when `declaring` data types. 54 | 55 | For example, the following code will not work 56 | 57 | ```haskell 58 | data Foo = Foo Int String deriving (Eq, Ord) 59 | ``` 60 | 61 | [Ref](https://github.com/purescript/documentation/blob/master/language/Differences-from-Haskell.md) 62 | 63 | ## Orphan Instances 64 | 65 | Hamler do not allow orphan instance. 66 | 67 | ## Operators 68 | 69 | ### No `,` operator 70 | 71 | ### No `>>` operator 72 | 73 | We prefer not to add (>>) for now, because the key word >> is reserved for binary syntax. We choose not to put a lot of operators for now. If there are needs, defining your own operator is allowed. 74 | 75 | ### Define Operators 76 | 77 | In you can define a operator like this in Haskell, but this is not allowed. 78 | 79 | ```haskell 80 | f $ x = f x -- Not Okay 81 | 82 | -- This is the way to do it 83 | apply f x = f 84 | x infixr 0 apply as $ 85 | ``` 86 | ## More 87 | 88 | ### No `undefined` 89 | 90 | -------------------------------------------------------------------------------- /guides/08_ForeignFunctionInterface.md: -------------------------------------------------------------------------------- 1 | # Foreign Function Interface 2 | 3 | [Toc] 4 | 5 | ## Use Erlang Code From Hamler 6 | 7 | Since Hamler compiles to CoreErlang, it makes sense that there should be some feature that allows you to call Erlang code from Hamler. This is a brief introduction to using Erlang code from Hamler. The FFI is a powerful feature, so you have to know what you are doing. One thing to keep in mind that though you can type foreign functions, Hamler has no way to check whether you have given the right type signature, so be careful and remember to keep impure code wrapped in IO. 8 | 9 | ## Foreign Import 10 | 11 | There are lot of examples in the [lib](https://github.com/hamler-lang/hamler/tree/master/lib) directory, from which you can easily discover that Erlang code and Hamler code are in the same directory with same filename, when defining a foreign function. 12 | 13 | For example, in `Data.Map` we defined datatype `Map`, so first define `Map` as a foreign imported datatype and give it its kind. 14 | 15 | ```haskell 16 | foreign import data Map :: Type -> Type -> Type 17 | ``` 18 | 19 | Then we can define some basic functions in erlang and import them to hamler. 20 | In Map.erl we have: 21 | 22 | ```erlang 23 | singleton(K, V) -> #{K => V}. 24 | ``` 25 | 26 | This is a function we defined to create a new map with one key to one value. 27 | 28 | In hamler we can easily import this with: 29 | 30 | ```haskell 31 | foreign import singleton :: forall k v. k -> v -> Map k v 32 | ``` 33 | 34 | The nice thing is that we can give `singleton` a type; however there is no way that Hamler can check this against the actual code you've written in Erlang. So when you are doing something not pure, remember to wrap the output with IO. 35 | 36 | ```haskell 37 | foreign import readFile :: String -> IO String 38 | ``` 39 | 40 | ## FFI Functions 41 | 42 | We have also provided some nice functions allowing you to "directly" use an Erlang library: 43 | 44 | ```haskell 45 | --if we want to use sin function from math module in Erlang 46 | sin :: Float -> Float 47 | sin = ffi1 :math :sin 48 | 49 | -- foreign import ffi1 :: forall a b. Atom -> Atom -> a -> b 50 | ``` 51 | 52 | Where `ffi1` is a function takes in two atoms to locate the function in the Erlang library, and the number 1 means this function needs argument. There are more in the lib. 53 | 54 | -------------------------------------------------------------------------------- /guides/05_HigherOrderFunctionsAndRecursions.md: -------------------------------------------------------------------------------- 1 | # Recursions and Higher Order Functions 2 | 3 | [ToC] 4 | 5 | ## Introduction 6 | 7 | Resursion is an important technique in programming, especially in functional programming. 8 | 9 | Simple examples: 10 | 11 | ```haskell 12 | fact :: Integer -> Integer 13 | fact 0 = 1 14 | fact n = n * fact (n - 1) 15 | 16 | > fact 10 17 | 3628800 18 | > fact 5 19 | 120 20 | 21 | fib :: Integer -> Integer 22 | fib 0 = 1 23 | fib 1 = 1 24 | fib n = fib (n - 1) + fib (n - 2) 25 | 26 | > fib 10 27 | 89 28 | > fib 5 29 | 8 30 | ``` 31 | 32 | ## Recursions on more complicated datatypes 33 | 34 | Definition of the datatype list is recursive. So,when we define a function for such datatypes, it comes naturally to define the function recursively. 35 | 36 | ```haskell 37 | length' :: forall a . [a] -> Integer 38 | length' [] = 0 39 | length' [x|xs] = 1 + length xs 40 | 41 | > length' "hamler" 42 | 6 43 | ``` 44 | 45 | ## Map, filter and fold 46 | 47 | `map`, `filter` and `foldr` are three commonly used functions to manipulate a list. `map` applys `f` on all `a`s in a list of `a`. `filter` just filters the list according to `p`. `foldr` destructs the list by replacing every `:` with a operator/or function. 48 | 49 | Here are the definitions. 50 | 51 | ```haskell 52 | map' :: forall a b. (a -> b) -> [a] -> [b] 53 | map' f [] = [] 54 | map' f [x|xs] = [f x | map' f xs] 55 | 56 | > map' (\x -> x +1 ) [1..10] 57 | [2,3,4,5,6,7,8,9,10,11] 58 | 59 | filter' :: forall a. (a -> Boolean) -> [a] -> [a] 60 | filter' p [] = [] 61 | filter' p [x|xs] = if p x 62 | then [x | filter p xs] 63 | else filter p xs 64 | 65 | > filter' (\x -> x > 5) [1..10] 66 | [6,7,8,9,10] 67 | 68 | foldl' :: forall a b. (b -> a -> b) -> b -> [a] -> b 69 | foldl' f k [] = k 70 | foldl' f k [x|xs] = foldl' f (f k x) xs 71 | 72 | > foldl' (+) 0 [1..10] 73 | 55 74 | ``` 75 | 76 | ## List Comprehensions 77 | 78 | There is an alternative way to define map and filter, which is to use list comprehension. 79 | 80 | ```haskell 81 | map f xs = [f x | x <- xs] 82 | filter p xs = [x | x <- xs, p x] 83 | ``` 84 | 85 | With list comprehension we can also do things like: 86 | 87 | ```haskell 88 | > [x + y | x <- [1..2], y<- [1..3]] 89 | [2,3,4,3,4,5] 90 | 91 | -- .. is syntax sugar for range 92 | > [1..10] 93 | [1,2,3,4,5,6,7,8,9,10] 94 | 95 | > ['a' .. 'z'] 96 | "abcdefghijklmnopqrstuvwxyz" 97 | ``` 98 | 99 | ## Higher Order Functions 100 | 101 | Functions like map, filter and foldr are also called higher order functions, because they take a function as their argument. A higher order function takes a function as its argument or/and returns a function as it's result. 102 | 103 | Here are some more examples of such functions. 104 | 105 | ```haskell 106 | apply :: forall a b. (a -> b) -> a -> b 107 | apply f x = f x 108 | 109 | compose :: forall a b. (b -> c) -> (a -> b) -> a -> c 110 | compose g f x = g (f x) 111 | ``` 112 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # The Hamler Language FAQ 2 | 3 | ## 1. About the Language 4 | 5 | ## 1.1 What does the Hamler Logo mean? 6 | 7 | **λE** = Lambda (**λ**) + **E**rlang VM. 8 | 9 | ![hamler-logo](https://www.hamler-lang.org/images/hamler@4x.png) 10 | 11 | ### 1.2 Elixir is already there, running on Erlang VM, how does this differ? 12 | 13 | **Hamler** is a completely different language from **Elixir**, though they are both compiled to beam bytecode and running on Erlang VM. 14 | 15 | 1. **Elixir** is a dynamically-typed functional programming language. **Hamler** is a strongly-typed functional language with type checking at compile-time. 16 | 17 | 2. **Elixir** has Ruby-like syntax, and the community mainly comes from Ruby On Rails. **Hamler** has Haskell and ML-style syntax, the core development team comes from Erlang and Haskell communities. 18 | 19 | 3. The design of **Hamler** compiler is also different from **Elixir**. **Hamler** source code is compiled to CoreErlang, while **Elixir** code is compiled to Erlang AST. 20 | 21 | ### 1.3 What are the differences between Hamler and Purerl? 22 | 23 | **Purerl** is a backend of PureScript language, which translates PureScript to Erlang source code. 24 | 25 | The **Hamler** compiler v0.1 is forked from PureScript v0.13.6. PureScript's Eco-system is mostly tailored for Javascript and NodeJS which is too limited for Erlang/OTP ecosystem if we just make **Hamler** a backend of PureScript. 26 | 27 | We introduced many Erlang data types as primary types, such as Erlang atoms, binaries, tuples, lists and maps. And at the same time, we have to modify the whole frontend (CST, AST, CoreFn and CodeGen) of PureScript to support expressions/syntax sugar from Erlang/OTP, such as binary match, list comprehensions, map pattern match... 28 | 29 | ### 1.4 What's the difference between Hamler and Haskell? 30 | 31 | **Hamler** is strictly evaluated, compiled to beam bytecode and running on Erlang VM, though it has the Haskell-style syntax. 32 | 33 | ### 1.5 How does hot code reloading work with static types, if the data types change between reloads? What's the upgrade story? 34 | 35 | The strongly-typed Hamler source code is compiled to dynamic CoreErlang finally. So, we think the hot-upgrade feature of Erlang should still work. 36 | 37 | 38 | ## 2. About the Compiler 39 | 40 | ### 2.1 Is the compiler forked from [PureScript][PureScriptHamler] project? 41 | 42 | Yes. Forked from [PureScript][PureScriptHamler] 0.13.6 43 | 44 | [PureScriptHamler]: https://github.com/hamler-lang/purescript 45 | 46 | 47 | ## 3. Install Packages 48 | 49 | ### 3.1 Is there a Windows install method? 50 | 51 | Not yet. Coming soon. 52 | 53 | 54 | ## 4. Tools and IDE 55 | 56 | ### 4.1 Does that mean the IDE support is there? 57 | 58 | IDE support, such as Vim, Emacs and VSCode, is still at the planning stage. 59 | 60 | 61 | ## 5. Milestones 62 | 63 | ### Is **Hamler** used by [**EMQ X**][EmqxGithub] project in any product already? 64 | 65 | No. Hamler v0.1 is far from being used in product applications. We are planning to introduce Hamler 1.0 in [**EMQ X**][EmqxGithub] v7.0 release. 66 | 67 | [emqxGithub]: https://github.com/emqx/ 68 | -------------------------------------------------------------------------------- /guides/02_QuickStart.md: -------------------------------------------------------------------------------- 1 | # Quick Start 2 | 3 | [ToC] 4 | 5 | ## Installation 6 | 7 | **Homebrew(macOS)** 8 | 9 | ```shell 10 | $ brew tap hamler-lang/hamler 11 | $ brew install hamler 12 | ``` 13 | 14 | **Install from source code(macOS)** 15 | 16 | 1. Install Erlang 17 | 18 | ```shell 19 | $ brew install erlang@23 20 | ``` 21 | 22 | 2. Install Stack 23 | 24 | Stack tutoriall https://docs.haskellstack.org/en/stable/install_and_upgrade/ 25 | 26 | 3. Clone from the Git repo 27 | 28 | ```shell 29 | $ git clone https://github.com/hamler-lang/hamler.git 30 | ``` 31 | 32 | 4. Install Hamler 33 | 34 | ```shell 35 | $ cd hamler 36 | $ make 37 | $ make install 38 | $ sudo mkdir -p /usr/local/lib/hamler/bin 39 | $ sudo cp repl/replsrv /usr/local/lib/hamler/bin/ 40 | $ sudo cp -rv lib /usr/local/lib/hamler/ 41 | $ sudo cp -rv ebin /usr/local/lib/hamler/ 42 | ``` 43 | 44 | ## Hamler Interpreter 45 | 46 | ```shell 47 | $ hamler repl 48 | > -- List, range and enums 49 | > [1,2,3] 50 | > [1..10] 51 | > ['a'..'z'] 52 | 53 | > -- erlang style maps 54 | > import Data.Map as Map 55 | > -- New map 56 | > m = #{"foo" => "bar", "bar" => "foo"} 57 | > -- Match Map 58 | > #{"foo" := a, "bar" := b} = m 59 | > -- get, put 60 | > Map.get "foo" m -- a = "bar" 61 | > Map.get "bar" m -- b = "foo" 62 | > m1 = Map.put "key" "val" 63 | > -- keys, values 64 | > keys = Map.keys m 65 | > values = Map.values m 66 | ``` 67 | 68 | ## Create A Project 69 | 70 | ```shell 71 | $ mkdir demo-project 72 | $ cd demo-project 73 | $ hamler init 74 | $ make 75 | $ make run 76 | ``` 77 | 78 | ## Module structure 79 | 80 | A module is simply a bunch of related functions, types and type classes. This makes a program a collection of modules. This helps organize your code and makes reusing some of the code easier. 81 | 82 | ### Module header 83 | 84 | **Module declaration** 85 | 86 | This how we declare a new module and specify which of the functions or types are exported. 87 | 88 | ```haskell 89 | module Hello (greet, farewell) where 90 | {- the module name can be a word or words separated by '.'; 91 | in this case it is just "Hello" -} 92 | 93 | greet :: String -> String 94 | greet n = "Hello " ++ n 95 | 96 | farewell :: String -> String 97 | farewell n = "Bye " ++ n 98 | ``` 99 | 100 | **Module import** 101 | 102 | The syntax for import in Hamler is `import `. This has to be done before defining any functions. One module can import as many as modules you wish, but there could be ambiguity when there are two things with the same name. 103 | 104 | ```haskell 105 | import Data.List --Modules are imported using their full names 106 | import Data.Maybe (isJust, isNothing) -- We can choose which functions to import 107 | import Data.Funtion as F 108 | -- We can deal with ambiguity by adding an alias. This means we need to add "F." before every function that is exposed from Data.Function to specify that it is from this module 109 | import Prelude hiding (fst) -- The Prelude is imported by default. By hiding `fst`, we can define our own version. 110 | ``` 111 | ## Hello, Hamler! 112 | 113 | ```haskell 114 | module Main where 115 | 116 | import Prelude 117 | 118 | main = print "Hello, World!" 119 | ``` 120 | -------------------------------------------------------------------------------- /guides/01_WhyHamler.md: -------------------------------------------------------------------------------- 1 | # Why Hamler? 2 | 3 | [ToC] 4 | 5 | For almost a decade, we have been developing software systems based on Erlang/OTP, especially our main product [EMQ X](https://github.com/emqx/emqx) - the scalable open-source MQTT broker. So, we have always believed that Erlang is a masterpiece of engineering. With amazing concurrency, distribution and fault tolerance, it is one of the few general-purpose language platforms able to properly handle concurrency and soft realtime. 6 | 7 | However, from all the experience writing Erlang, we believe that the following features can help Erlang programmer better adapt to the coming wave of 5G, IoT and edge-programming and attract more people for using BEAM. 8 | 9 | - Compile-time type checking and type reference 10 | - ADTs, Function Composition, Type Classes 11 | - More friendly syntax for prosperous communities 12 | - Functor, Applicative and Monad...:) 13 | 14 | Now all the features are avaliable in the Hamler programming language. 15 | 16 | ## What's Hamler 17 | 18 | `Hamler` A Haskell-style functional programming language running on Erlang VM. 19 | 20 | It is a strongly-typed language with compile-time typechecking and built-in support for concurrency and distribution. This makes it perfect for building the next generation of scalable, reliable, realtime applications, especially for 5G, IoT and edge computing. 21 | 22 | Cool, let's quit the bragging and kick off. 23 | 24 | ## Prerequisites 25 | 26 | - Basic Programming Skills 27 | 28 | - It will be good to have some experience with Haskell or Erlang (but this is not essential) 29 | 30 | ## Haskell Style 31 | 32 | First of all, Hamler is purely functional. It has really similar syntax to Haskell, so if you are familiar with Haskell it should not be a problem. However, if you are not, the guide should be able to walk through the basic syntax and make you more comfortable with programming functionally. 33 | 34 | This is an example of implementing merge sort in Hamler. It is normal that you don't understand what is going on, the purpose of the example is to just let you get a gist of what will the code look like. 35 | 36 | ```haskell 37 | merge :: forall a. Ord a => [a] -> [a] -> [a] 38 | merge [] ys = ys 39 | merge xs [] = xs 40 | merge [x|xs] [y|ys] = if x <= y 41 | then [x |merge xs [y|ys]] 42 | else [y |merge [x|xs] ys] 43 | 44 | mergesort :: forall a. Ord a => [a] -> [a] 45 | mergesort [] = [] 46 | mergesort [x] = [x] 47 | mergesort xs = let (as, bs) = splitAt (length xs / 2) xs 48 | in merge (mergesort as) (mergesort bs) 49 | ``` 50 | 51 | ## Type Checking 52 | 53 | Hamler is strongly typed with compile type checking. So at compile time we can ensure that our program is type-safe, and this can help programmers to avoid silly mistakes like adding a string and an integer. 54 | 55 | ## Erlang and Concurrency 56 | 57 | Erlang is famous for its concurrency. Concurrent programming can be used to improve performance, gain scalability and fault-tolerance. **BEAM** is the virtual machine at the core of the Erlang Open Telecom Platform (OTP) which enables it to happen. By compiling Hamler to CoreErlang, we can essentially take advantage of Erlang VM. 58 | 59 | ```haskell 60 | import Prelude 61 | import Data.List as L 62 | 63 | start :: IO () 64 | start = do 65 | pid0 <- getSelf 66 | pids <- seqio [spawn $ loop (State pid0) | x <- [1..1000]] 67 | seqio [send j (Next i) | (i,j) <- (zip pids [last pids|L.init pids]) ] 68 | send (head pids) (Trans "great hamler! " 0) 69 | return () 70 | 71 | data Message = Next Pid 72 | | Trans String Integer 73 | 74 | data State = State Pid 75 | 76 | handleMsg :: State -> Message -> IO State 77 | handleMsg (State pid) (Next p) = return (State p) 78 | handleMsg (State pid) (Trans str 1111) = return (State pid) 79 | handleMsg (State pid) (Trans str i) = 80 | do send pid (Trans str (i+1)) 81 | pid0 <- getSelf 82 | println (show pid0 <> " -> " <> show pid <> ": " <> str <> show i) 83 | return (State pid) 84 | 85 | loop :: State -> IO () 86 | loop s = receive v -> handleMsg s v >>= loop 87 | ``` 88 | -------------------------------------------------------------------------------- /guides/10_MessagePassingConcurrency.md: -------------------------------------------------------------------------------- 1 | # Message Passing Concurrency 2 | 3 | [ToC] 4 | 5 | ## About Actor Model 6 | 7 | Professor Carl Hewitt published the famous paper [*Actor model of computation*](https://arxiv.org/vc/arxiv/papers/1008/1008.1459v8.pdf) in 1974. In the thesis, he elaborates that: 8 | 9 | An Actor is a computational entity that, in response to a message it receives, can concurrently: 10 | 11 | - send a finite number of messages to other Actors; 12 | - create a finite number of new Actors; 13 | - designate the behavior to be used for the next message it receives. 14 | 15 | With the rise of multi-core computing and large-scale distributed systems, the Actor Model is becoming increasingly important because of its natural concurrent, parallel, and distributed. 16 | 17 | ## Process and Mailbox 18 | 19 | An actor in Hamler/Erlang is defined as a process, which works like an OS process. Each process has its own memory, composed of a mailbox, a heap, a stack and a process control block(PCB) with information about the process. 20 | 21 | ![Process](https://www.hamler-lang.org/images/process@1x.png) 22 | 23 | Processes in Erlang are very lightweight. We can create millions of processes on a running Erlang virtual machine. 24 | 25 | A process is identified by a Pid. Other processes can send messages to a process via Pid. 26 | 27 | ## A Ping/Pong Example 28 | 29 | ```haskell 30 | import Prelude 31 | 32 | go :: Process () 33 | go = do 34 | self <- getSelf 35 | pid <- spawn loop 36 | pid ! (self, :ping) 37 | receive 38 | :pong -> println "Pong!" 39 | pid ! :stop 40 | 41 | loop :: Process () 42 | loop = 43 | receive 44 | (from, :ping) -> do 45 | println "Ping!" 46 | from ! :pong 47 | loop 48 | :stop -> return () 49 | ``` 50 | 51 | ## Spawn a new process 52 | 53 | In Hamler, a new process is created via the `spawn` functions, which are defined in `Control.Process.Spawn` module. 54 | 55 | ```haskell 56 | -- | Create a process 57 | spawn :: forall a. IO a -> Process Pid 58 | 59 | -- | Create and link a process 60 | spawnLink :: forall a. IO a -> Process Pid 61 | 62 | -- | Create and monitor a process 63 | spawnMonitor :: forall a. IO a -> Process (Pid, Ref) 64 | ``` 65 | 66 | ## Send/Receive message 67 | 68 | ```haskell 69 | go :: Process () 70 | go = do 71 | pid <- spawn recv 72 | pid ! :msg 73 | 74 | recv :: Process () 75 | recv = receive x -> printf "recv: %s" (showAny x) 76 | ``` 77 | 78 | ## Selective Receive 79 | 80 | ```haskell 81 | go :: Process () 82 | go = do 83 | pid <- spawn selectiveRecv 84 | pid ! :bar 85 | pid ! :foo 86 | 87 | selectiveRecv :: Process () 88 | selectiveRecv = do 89 | receive :foo -> println "foo" 90 | receive :bar -> println "bar" 91 | ``` 92 | 93 | ## Receive ... after 94 | 95 | ```haskell 96 | go :: Process () 97 | go = do 98 | pid <- spawn recvAfter 99 | pid ! :foo 100 | 101 | recvAfter :: Process () 102 | recvAfter = 103 | receive 104 | :bar -> println "recv bar" 105 | after 106 | 1000 -> println "timeout" 107 | ``` 108 | 109 | ## Registered Processes 110 | 111 | A process can be registered under a name, which has an Atom type. 112 | 113 | ```haskell 114 | import Control.Process (register, whereis, unregister) 115 | 116 | go :: Process () 117 | go = do 118 | pid <- spawn proc 119 | register :name pid 120 | res <- whereis :name 121 | unregister :name 122 | 123 | proc :: Process () 124 | proc = receive _ -> return () 125 | ``` 126 | 127 | ## Linking 128 | 129 | Two processes can be linked to each other. 130 | 131 | ```haskell 132 | import Prelude 133 | import Control.Process (killProc, trapExit) 134 | 135 | go :: forall a. Process a 136 | go = do 137 | trapExit true 138 | pid <- spawn (receive _ -> return ()) 139 | link pid 140 | killProc pid 141 | receive msg -> return msg 142 | ``` 143 | 144 | ## Monitoring 145 | 146 | One process `Pid1` can monitor another process `Pid2`. If `Pid2` terminates, `Pid1` will receive a 'DOWN' message from `Pid2`. 147 | 148 | ```haskell 149 | import Prelude 150 | import Control.Process (killProc) 151 | 152 | go :: forall a. IO a 153 | go = do 154 | pid <- spawn proc 155 | ref <- monitor pid 156 | killProc pid 157 | receive msg -> return msg 158 | 159 | proc :: Process () 160 | proc = receive _ -> return () 161 | ``` 162 | 163 | ## Process Termination 164 | 165 | ```haskell 166 | import Prelude 167 | import Control.Process (isAlive, exitProc) 168 | 169 | -- Exit the current process 170 | exit :normal 171 | 172 | go :: Process Boolean 173 | go = do 174 | pid <- spawn (receive _ -> return ()) 175 | exitProc pid :reason 176 | isAlive pid 177 | ``` 178 | 179 | -------------------------------------------------------------------------------- /guides/04_MoreTypesandPatternMatching.md: -------------------------------------------------------------------------------- 1 | # More Types and Pattern Matching 2 | 3 | [ToC] 4 | 5 | ## Algebraic Data Types 6 | 7 | Using algebraic data types we are saying some datatype can be one of the many things, distinguished by and identified by what is called a constructor. 8 | 9 | For example, `Maybe a` is saying that If something has type Maybe a, it can either be a value which has an `a ` type and wrapped by a constructor `Just` or an empty value `Nothing` 10 | 11 | ```haskell 12 | data Maybe a = Just a 13 | | Nothing 14 | ``` 15 | 16 | Another example is `List`, from its definition we can see that it has a recursive structure. So we can have whatever number of elements in our list, but they have to have the same type. 17 | 18 | ```haskell 19 | data List a = Cons a (List a) 20 | | Empty 21 | ``` 22 | 23 | ## Newtypes 24 | 25 | `newtype`s are used to distinguish two types which have the same type of value but different units/meanings. 26 | 27 | For example: 28 | 29 | ```haskell 30 | newtype Email = Email String 31 | 32 | m1 :: Map Email Integer 33 | m1 = empty 34 | --This forces us to only pass a String with a construtor Email. 35 | --So insert "abc" 123 m1 will fail 36 | ``` 37 | 38 | ## Simple Pattern Matching 39 | 40 | ```haskell 41 | fib 0 = 1 42 | fib 1 = 1 43 | fib x = fib (x - 1) + fib (x - 2) 44 | ``` 45 | 46 | ## Guards 47 | 48 | ```haskell 49 | max x y | x > y = x 50 | | otherwise = y 51 | ``` 52 | 53 | ## List Patterns 54 | 55 | ```haskell 56 | isEmpty :: forall a. [a] -> Boolean 57 | isEmpty [] = true 58 | isEmpty [x|xs] = false 59 | ``` 60 | 61 | ## Record Patterns 62 | 63 | ```haskell 64 | showPerson :: { firstName :: Name, lastName :: Name } -> Name 65 | showPerson { firstName: x, lastName: y } = y <> ", " <> x 66 | 67 | > showPerson { firstName = "Phil", lastName = "Freeman" } 68 | "Freeman, Phil" 69 | 70 | > showPerson { firstName = "Phil", lastName = "Freeman", location = "Los Angeles" } 71 | "Freeman, Phil" 72 | ``` 73 | 74 | ## Maps 75 | 76 | Map is the `Map` from Erlang. `Map k v` is the type of a Map. 77 | 78 | We can construct a Map like this: 79 | 80 | ```haskell 81 | m1 :: Map String Integer 82 | m1 = #{"Hello" => 5, "World" => 17} 83 | 84 | > lookup m1 "Hello" 85 | Just 5 86 | 87 | > insert "!" 0 m1 88 | #{"Hello" => 5, "World" => 17, "!" => 0} 89 | ``` 90 | 91 | ## Map Patterns 92 | 93 | We can also pattern match on `Map`s, and this is very similar to `Record`s, except for some syntax changes. For example, `getID` let us get the ID of Wang from a map where we have to have at least Wang, Thomas and Leeming as keys. 94 | 95 | ```haskell 96 | getID :: Map String Integer -> Maybe Integer 97 | getID #{ "Wang":= x, "Thomas" := y, "Leeming" := z } = Just x 98 | getID _ = Nothing 99 | 100 | > getID #{"Wang" => 10, "Thomas" => 20 , "Leeming" => 30 } 101 | {'Just',10} 102 | ``` 103 | 104 | ## Binary Patterns 105 | 106 | Matching on binaries is just like how it is done in Erlang. In the following example, we are trying to get a 24-bit integer out of the Binary passed to `getA`. 107 | 108 | ```haskell 109 | getA :: Binary -> Maybe (Integer, Binary, Binary) 110 | getA << a:24/big-integer , b:4/binary-little , c:3/binary >> = Just (a,b,c) 111 | getA _ = Nothing 112 | 113 | > getA <<0,0,1,"aaaa","bbb">> 114 | {'Just',{1,<<"aaaa">>,<<"bbb">>}} 115 | 116 | > getA <<0,0,1,"aaaa","bb">> 117 | {'Nothing'} 118 | 119 | getB :: Binary -> Maybe (Integer, Binary, Binary) 120 | getB << a:24/big-integer , b:4/binary-little , c/binary >> = Just (a,b,c) 121 | getB _ = Nothing 122 | 123 | > getB <<0,0,1,"aaaa">> 124 | {'Just',{1,<<"aaaa">>,<<>>}} 125 | 126 | > getB <<0,0,1,"aaaa","bbbbbbbbb">> 127 | {'Just',{1,<<"aaaa">>,<<"bbbbbbbbb">>}} 128 | ``` 129 | 130 | `Big` and `Little` means the endianess in the part we need. `Integer` or `Binary` is the type we will give to after we extract the segment. The number of bits of the segment depends on the size of the segment we need and the type we assign. If they type we assign is an `Integer` then we get exact the same number of the `size` of bits, which is required to be evenly divisible by 8. If it is a `Binary` we want, it will need 8 times the size of bits. 131 | 132 | ## Case Expressions 133 | 134 | With `case` we can also pattern match on the value after some computations when there is no need to bind the intermediate result. 135 | 136 | ```haskell 137 | plus :: (Integer, Integer) -> Integer 138 | plus (x, y) = x + y 139 | 140 | sumUpTo :: Integer -> (Integer, Integer) -> Boolean 141 | sumUpTo x p = case plus p of 142 | 10 -> true 143 | _ -> false 144 | > sumUpTo 1 (2,3) 145 | false 146 | 147 | > sumUpTo 1 (2,8) 148 | true 149 | ``` 150 | -------------------------------------------------------------------------------- /guides/13_DifferencesFromErlang.md: -------------------------------------------------------------------------------- 1 | # Differences from Erlang 2 | 3 | [Toc] 4 | 5 | ## Overview 6 | 7 | Hamler has a very different syntax from Erlang, although Hamler source's code is compiled into CoreErlang. Erlang's syntax comes primarily from Prolog, while Hamler's comes from Haskell and Standard ML. 8 | 9 | ## Variables 10 | 11 | Variable names in both Hamler and Erlang are composed of letters, digits, and underscores. However, variables in Hamler begin with a lowercase letter, while Erlang's variables begin with a capital letter. 12 | 13 | Hamler: 14 | ```hamler 15 | a, b, _a, _ 16 | the_1st_var 17 | ``` 18 | 19 | Erlang: 20 | ```erlang 21 | A, B, _A, _ 22 | The_1st_var 23 | ``` 24 | 25 | ## Delimiters 26 | 27 | Unlike Erlang, Hamler language do not require `,`, `;`, and `.` delimiters. 28 | 29 | ## Comments 30 | 31 | Single line comments in Hamler start with `--`: 32 | ```hamler 33 | -- A single line comment 34 | ``` 35 | 36 | Comments in Erlang start with `%`: 37 | ```erlang 38 | %% erlang comment 39 | ``` 40 | 41 | ## Functions 42 | 43 | ### Function Definition and Application 44 | 45 | Hamler: 46 | ```hamler 47 | add x y = x + y 48 | add 3 4 -- return 7 49 | 50 | factorial 0 = 1 51 | factorial n = n * factorial (n - 1) 52 | 53 | factorial 10 -- return 3628800 54 | ``` 55 | 56 | Erlang: 57 | ```erlang 58 | add(X, Y) -> X + Y. 59 | add(3, 4). %% return 7 60 | 61 | factorial(0) -> 1; 62 | factorial(N) -> N * factorial(N - 1). 63 | 64 | factorial(10). %% return 3628800 65 | ``` 66 | 67 | ### Anonymous Functions 68 | 69 | Hamler: 70 | ```hamler 71 | add = \a b -> a + b 72 | curried_add = \a -> \b -> a + b 73 | 74 | add 2 3 75 | curried_add 2 3 76 | ``` 77 | 78 | Erlang: 79 | ```erlang 80 | Add = fun(X, Y) -> X + Y end. 81 | CurriedAdd = fun(X) -> fun(Y) -> X + Y end end. 82 | 83 | Add(2,3). 84 | (CurriedAdd(2))(3). 85 | ``` 86 | 87 | ### Guards in Function 88 | 89 | Hamler: 90 | ```hamler 91 | f :: Integer -> String 92 | f n | n > 0 = "Positive Integer" 93 | | n < 0 = "Negative Integer" 94 | | otherwise = "Zero" 95 | ``` 96 | 97 | Erlang: 98 | ```erlang 99 | f(N) when N > 0 -> "Positive Integer"; 100 | f(N) when N < 0 -> "Negative Integer"; 101 | f(_) -> "Zero". 102 | ``` 103 | 104 | ## Data Types 105 | 106 | ### Atoms 107 | ### Binaries 108 | ### Chars 109 | ### Integers 110 | ### Tuples 111 | 112 | ## List Comprehensions 113 | 114 | List comprehensions in Erlang use `||` as a separator between expression and generators, but `|` is used in Hamler. 115 | 116 | Hamler: 117 | ```hamler 118 | [x*2 | x <- [1,2,3]] -- [2,4,6] 119 | 120 | -- multiple generators 121 | [(x,y) | x <- [1,2,3], y <- [4,5]] 122 | 123 | -- dependent generators 124 | [(x,y) | x <- [1..3], y <- [x..3]] 125 | 126 | -- Conditions 127 | even i = 0 == i % 2 128 | [x | x <- [1..10], even x] 129 | ``` 130 | 131 | Erlang: 132 | ```erlang 133 | [X*2 || X <- [1,2,3]]. %% [2,4,6] 134 | 135 | -- multiple generators 136 | [{X, Y} || X <- [1,2,3], Y <- [4,5]]. 137 | 138 | -- dependent generators 139 | [{X, Y} || X <- [1,2,3], Y <- lists:seq(X,3)]. 140 | 141 | -- Conditions 142 | even(I) -> 0 == (I rem 2). 143 | [X || X <- lists:seq(1, 10), even(X)]. 144 | ``` 145 | 146 | ## Expressions 147 | 148 | ### case .. of 149 | 150 | The `case` expression in Hamler is the same as Haskell. 151 | 152 | Hamler: 153 | ```hamler 154 | data RGB = Red | Green | Blue 155 | color = Green 156 | case color of 157 | Red -> "Red" 158 | Green -> "Green" 159 | Blue -> "Blue" 160 | ``` 161 | 162 | `case` expression in Erlang ends with an `end` keyword. 163 | 164 | Erlang: 165 | ```erlang 166 | Color = green. 167 | case Color of 168 | red -> "Red"; 169 | green -> "Green"; 170 | blue -> "Blue" 171 | end. 172 | ``` 173 | 174 | ### if .. then .. else 175 | 176 | Hamler: 177 | ```hamler 178 | -- Every `then` must have a corresponding `else` 179 | max x y = if x > y then x else y 180 | ``` 181 | 182 | Erlang: 183 | ```erlang 184 | max(X, Y) -> if X > Y -> X; true -> Y end. 185 | ``` 186 | 187 | ### let and where bindings 188 | 189 | There are no `let` and `where` bindings in Erlang 190 | 191 | Hamler: 192 | ``` 193 | let n = 1 + 2 194 | 195 | z = let x = 3 196 | y = 2 * x 197 | in x * y 198 | 199 | -- or 200 | z = x * y 201 | where 202 | x = 3 203 | y = 5 204 | ``` 205 | 206 | ## Operators 207 | 208 | ### Arithmetic Operators 209 | 210 | | Erlang | Hamler | Description | 211 | | -------- | ---------------- | ---------------- | 212 | | rem | % | Remain | 213 | | div | Not available | Integer Division | 214 | 215 | 216 | ### Logical Operators 217 | 218 | | Erlang | Hamler | Description | 219 | | -------- | ---------------- | ---------------- | 220 | | and | Not available | | 221 | | andalso | && | And also | 222 | | or | Not available | | 223 | | orelse | \|\| | Or else | 224 | 225 | ### Relational Operators 226 | 227 | | Erlang | Hamler | Description | 228 | | -------- | ---------------- | ---------------- | 229 | | =:= | Not available | Exactly equal | 230 | | =/= | Not available | Exactly not equal| 231 | | =< | <= | Less equal | 232 | 233 | ## Modules 234 | 235 | The module system of Hamler is the same as Haskell, which is more advanced than Erlang. 236 | 237 | -------------------------------------------------------------------------------- /guides/03_BasicTypesFunctionsAndOperators.md: -------------------------------------------------------------------------------- 1 | # Basic Types, Functions and Operators 2 | 3 | [ToC] 4 | 5 | ## Simple Types 6 | 7 | Hamler is strongly typed, and has a powerful static type system. Let's start with some simple examples. 8 | 9 | **Boolean** 10 | 11 | ```haskell 12 | true :: Boolean 13 | false :: Boolean 14 | ``` 15 | 16 | **Numbers** 17 | 18 | Hamler has Integer and Float, and since they have different types so they can't be mixed. 19 | 20 | ```haskell 21 | --Integer 22 | 1 :: Integer 23 | 24 | --Float 25 | 0.1 :: Float 26 | ``` 27 | 28 | **Atoms** 29 | 30 | Atom is probably more familiar to Erlang user. It is a literal, a constant with a name starting with `:` . 31 | 32 | ``` 33 | :hello 34 | :world 35 | ``` 36 | 37 | **Strings** 38 | 39 | In Hamler `String` is just a list of `Char` 40 | 41 | ```haskell 42 | "Hello World" :: String -- ['H','e','l','l','o',',','W','o','r','l','d'] 43 | ``` 44 | 45 | **Binaries** 46 | 47 | 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](https://erlang.org/doc/man/binary.html) should be helpful for some intuition. 48 | 49 | ```haskell 50 | <<1,2,3:8,4:16,5,"abcdefg">> :: Binary 51 | ``` 52 | 53 | ## Operators 54 | 55 | | Operator | Meaning | | Operator | Meaning | 56 | | -------- | ---------------------- | ---- | -------- | --------------------- | 57 | | + | Numeric addition | | == | Equality check | 58 | | - | Numeric subtraction | | < | Less than | 59 | | * | Numeric multiplication | | <= | Less than or equal | 60 | | / | Numeric division (div) | | > | Greater than | 61 | | % | Remainder | | >= | Greater than or equal | 62 | | && | Boolean AND | | \|\| | Boolean OR | 63 | 64 | ## Functions 65 | 66 | 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. 67 | 68 | ```haskell 69 | double :: Integer -> Integer 70 | double x = x * 2 71 | ``` 72 | 73 | **Lambda Expression** 74 | 75 | There are also lambda expressions in Hamler, here is an example of how we rewrite double. 76 | 77 | ```haskell 78 | double' :: Integer -> Integer 79 | double' = \x -> 2 * x 80 | ``` 81 | 82 | It becomes really handy when we need to make an anonymous function. 83 | 84 | **Currying** 85 | 86 | ```haskell 87 | --Curry 88 | --This is uncurried (+) 89 | add :: (Integer, Integer) -> Integer 90 | add (x, y) = x + y 91 | 92 | --This is curried (+) 93 | plus :: Integer -> Integer -> Integer 94 | plus x y = x + y 95 | ``` 96 | 97 | **Partial Application** 98 | 99 | ```haskell 100 | -- plus :: Integer -> (Integer -> Integer) This is one of the example of higher order functions 101 | >:t plus 2 102 | plus 2:: Integer -> Integer 103 | >let plusTwo = plus2 104 | >plusTwo 3 105 | 5 106 | ``` 107 | 108 | ## Quantified Types 109 | 110 | They are also known as **polymorphic types**. 111 | 112 | ```haskell 113 | > :type id 114 | id :: forall a. a -> a 115 | ``` 116 | 117 | The key word `forall` indicates that `id` is univerally quantified, meaning that `id` can be applied to any type. 118 | 119 | ```haskell 120 | > id 1 121 | 1 122 | ``` 123 | 124 | A more complicated example is `flip`. `flip` is also a [higher-order function](05_HigherOrderFunctionsAndRecursions.md), which will be explained in a later chapter. 125 | 126 | ```haskell 127 | > :type flip 128 | forall a b c. (a -> b -> c) - > b -> a -> c 129 | ``` 130 | 131 | ## Notes On Indentations 132 | 133 | Like 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. 134 | 135 | ```haskell 136 | flip x f = f 137 | x -- NOT OKAY, Hamler will see x as a seperate declaration 138 | 139 | flip f x = f 140 | x -- OKAY, but not recommended 141 | ``` 142 | 143 | **`Let` and `Where` Bindings** 144 | 145 | Keywords such as let and where introduce a new block, where further indentation is needed. 146 | 147 | ```haskell 148 | distance x y = sqrt z 149 | where 150 | z = x' + y' 151 | x' = x * x 152 | y' = y * y 153 | ``` 154 | 155 | ## Type Synonym 156 | 157 | Type synonym can be used to simplify a long type name to make the code more readable. 158 | 159 | ```haskell 160 | >:i String 161 | type String = [Char] 162 | ``` 163 | 164 | Or you can define you own synonym name or a record. 165 | 166 | ## Records 167 | 168 | ```haskell 169 | type Name = String 170 | 171 | type Person = 172 | { firstName :: Name 173 | , secondName :: Name 174 | } 175 | 176 | {- 177 | This is syntax sugared 178 | "type Person = Record (FirstName :: Name , SecondName :: Name)" 179 | -} 180 | ``` 181 | 182 | Fields can be accessed by `.` 183 | 184 | ```haskell 185 | leader :: Person 186 | leader = {firstName = "John", lastName = "Portsman"} 187 | 188 | >leader.firstName 189 | "John" 190 | ``` 191 | 192 | This is how we update a record. 193 | 194 | ```haskell 195 | newLeader :: Person 196 | newLeader = leader{firstName = "James"} 197 | 198 | >newLeader.firstName 199 | "James" 200 | ``` 201 | 202 | ```haskell 203 | a = { name = "yang" 204 | , position = 205 | { streetNumber = 232 206 | , location = { x = 12.223 207 | , y = 45.9 208 | } 209 | } 210 | } 211 | 212 | b = a{position.location.x = 10.003} 213 | 214 | 215 | > a.position.location.x 216 | 12.223 217 | > b.position.location.x 218 | 10.003 219 | 220 | ``` 221 | 222 | ```haskell 223 | a = { name = "yang" 224 | , pos ={ x = 10 225 | , y = 20 226 | , info = { s = "val" 227 | , v = 45.9 228 | } 229 | } 230 | } 231 | 232 | b = a{pos.info.s = "newVal"} 233 | ``` -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Documentation of Hamler 2 | 3 | ![hamler-logo](https://www.hamler-lang.org/images/hamler@2x.png) 4 | 5 | ## [**Cheatsheet**](Cheatsheet.md) 6 | 7 | ## [**Guides**](guides/) 8 | 9 | 01. [**Why Hamler?**](guides/01_WhyHamler.md) 10 | - [What's Hamler](guides/01_WhyHamler.md#whats-hamler) 11 | - [Prerequisites](guides/01_WhyHamler.md#prerequisites) 12 | - [Haskell Style](guides/01_WhyHamler.md#haskell-style) 13 | - [Type Checking](guides/01_WhyHamler.md#type-checking) 14 | - [Erlang and Concurrency](guides/01_WhyHamler.md#erlang-and-concurrency) 15 | 16 | 02. [**Quick Start**](guides/02_QuickStart.md) 17 | - [Installation](guides/02_QuickStart.md#installation) 18 | - [Hamler Interpreter](guides/02_QuickStart.md#hamler-interpreter) 19 | - [Create A Project](guides/02_QuickStart.md#create-a-project) 20 | - [Module Structure](guides/02_QuickStart.md#module-structure) 21 | - [Hello Hamler](guides/02_QuickStart.md#hello-hamler-) 22 | 23 | 03. [**Basic Types, Functions and Operators**](guides/03_BasicTypesFunctionsAndOperators.md) 24 | - [Simple Types](guides/03_BasicTypesFunctionsAndOperators.md#simple-types) 25 | - [Operators](guides/03_BasicTypesFunctionsAndOperators.md#operators) 26 | - [Functions](guides/03_BasicTypesFunctionsAndOperators.md#functions) 27 | - [Quantified Types](guides/03_BasicTypesFunctionsAndOperators.md#quantified-types) 28 | - [Notes on Indentations](guides/03_BasicTypesFunctionsAndOperators.md#notes-on-indentations) 29 | - [Type Synynom](guides/03_BasicTypesFunctionsAndOperators.md#type-synynom) 30 | - [Records](guides/03_BasicTypesFunctionsAndOperators.md#records) 31 | 32 | 04. [**More Types and Pattern Matching**](guides/04_MoreTypesandPatternMatching.md) 33 | - [Algebraic Data Types](guides/04_MoreTypesandPatternMatching.md#algebraic-data-types) 34 | - [Newtypes](guides/04_MoreTypesandPatternMatching.md#newtypes) 35 | - [Simple Pattern Matching](guides/04_MoreTypesandPatternMatching.md#simple-pattern-matching) 36 | - [Guards](guides/04_MoreTypesandPatternMatching.md#guards) 37 | - [List Patterns](guides/04_MoreTypesandPatternMatching.md#list-patterns) 38 | - [Record Patterns](guides/04_MoreTypesandPatternMatching.md#record-patterns) 39 | - [Maps](guides/04_MoreTypesandPatternMatching.md#maps) 40 | - [Map Patterns](guides/04_MoreTypesandPatternMatching.md#map-patterns) 41 | - [Binary Patterns](guides/04_MoreTypesandPatternMatching.md#binary-patterns) 42 | - [Case Expressions](guides/04_MoreTypesandPatternMatching.md#case-expressions) 43 | 44 | 05. [**High Order Functions And Recursions**](guides/05_HigherOrderFunctionsAndRecursions.md) 45 | - [Introduction](guides/05_HigherOrderFunctionsAndRecursions.md#introduction) 46 | - [Recursions on more complicated datatypes](guides/05_HigherOrderFunctionsAndRecursions.md#recursions-on-more-complicated-datatypes) 47 | - [Map, filter and fold](guides/05_HigherOrderFunctionsAndRecursions.md#map-filter-and-fold) 48 | - [List Comprehensions](guides/05_HigherOrderFunctionsAndRecursions.md#list-comprehensions) 49 | - [Higher Order Functions](guides/05_HigherOrderFunctionsAndRecursions.md#higher-order-functions) 50 | 51 | 06. [**Type Classes**](guides/06_TypeClasses.md) 52 | - [Introduction](guides/06_TypeClasses.md#introduction) 53 | - [Functor](guides/06_TypeClasses.md#functor) 54 | - [Common type classes](guides/06_TypeClasses.md#common-type-classes) 55 | 56 | 07. [**Applicative and Monad**](guides/07_ApplicativeAndMonad.md) 57 | - [Functor](guides/07_ApplicativeAndMonad.md#functor) 58 | - [Applicative](guides/07_ApplicativeAndMonad.md#applicative) 59 | - [Monad](guides/07_ApplicativeAndMonad.md#monad) 60 | - [Lifting](guides/07_ApplicativeAndMonad.md#lifting) 61 | 62 | 08. [**Foreign Function Interface**](guides/08_ForeignFunctionInterface.md) 63 | - [Use Erlang Code From Hamler](guides/08_ForeignFunctionInterface.md#use-erlang-code-from-hamler) 64 | - [Foreign Import](guides/08_ForeignFunctionInterface.md#foreign-import) 65 | - [FFI Functions](guides/08_ForeignFunctionInterface.md#ffi-functions) 66 | 67 | 09. [**Data Types Mapping**](guides/09_DataTypesMapping.md) 68 | - [Overview](guides/09_DataTypesMapping.md#overview) 69 | - [Atoms Mapping](guides/09_DataTypesMapping.md#atoms-mapping) 70 | - [Booleans Mapping](guides/09_DataTypesMapping.md#booleans-mapping) 71 | - [Chars Mapping](guides/09_DataTypesMapping.md#chars-mapping) 72 | - [Integers Mapping](guides/09_DataTypesMapping.md#integers-mapping) 73 | - [Floats Mapping](guides/09_DataTypesMapping.md#floats-mapping) 74 | - [Strings Mapping](guides/09_DataTypesMapping.md#strings-mapping) 75 | - [Tuples Mapping](guides/09_DataTypesMapping.md#tuples-mapping) 76 | - [Lists Mapping](guides/09_DataTypesMapping.md#lists-mapping) 77 | - [Enum, Range](guides/09_DataTypesMapping.md#enum-range) 78 | - [Maps Mapping](guides/09_DataTypesMapping.md#maps-mapping) 79 | - [Records Mapping](guides/09_DataTypesMapping.md#records-mapping) 80 | - [Binaries Mapping](guides/09_DataTypesMapping.md#binaries-mapping) 81 | - [Ports Mapping](guides/09_DataTypesMapping.md#ports-mapping) 82 | - [Pids Mapping](guides/09_DataTypesMapping.md#pids-mapping) 83 | - [References Mapping](guides/09_DataTypesMapping.md#references-mapping) 84 | - [User-defined data types Mapping](guides/09_DataTypesMapping.md#user-defined-data-types-mapping) 85 | 86 | 10. [**Message Passing Concurrency**](guides/10_MessagePassingConcurrency.md) 87 | - [About Actor Model](guides/10_MessagePassingConcurrency.md#about-actor-model) 88 | - [Process and Mailbox](guides/10_MessagePassingConcurrency.md#process-and-mailbox) 89 | - [A Ping/Pong Example](guides/10_MessagePassingConcurrency.md#a-pingpong-example) 90 | - [Spawn a new process](guides/10_MessagePassingConcurrency.md#spawn-a-new-process) 91 | - [Send/Receive message](guides/10_MessagePassingConcurrency.md#sendreceive-message) 92 | - [Selective Receive](guides/10_MessagePassingConcurrency.md#selective-receive) 93 | - [Receive .. after](guides/10_MessagePassingConcurrency.md#receive--after) 94 | - [Registered Processes](guides/10_MessagePassingConcurrency.md#registered-processes) 95 | - [Linking](guides/10_MessagePassingConcurrency.m#linking) 96 | - [Monitoring](guides/10_MessagePassingConcurrency.m#monitoring) 97 | - [Process Termination](guides/10_MessagePassingConcurrency.md#process-termination) 98 | 99 | 11. [**OTP Behaviours**](guides/11_OTPBehaviours.md) 100 | - [Overview](guides/11_OTPBehaviours.md#overview) 101 | - [GenServer](guides/11_OTPBehaviours.md#genserver) 102 | - [GenStatem](guides/11_OTPBehaviours.md#genstatem) 103 | - [GenEvent](guides/11_OTPBehaviours.md#genevent) 104 | - [Supervisor](guides/11_OTPBehaviours.md#supervisor) 105 | 106 | 12. [**Node and Distributed Erlang**](guides/12_NodeAndDistributedErlang.md) 107 | - [Distributed Erlang/OTP](guides/12_NodeAndDistributedErlang.md#distributed-erlangotp) 108 | - [Connect Nodes](guides/12_NodeAndDistributedErlang.md#connect-nodes) 109 | - [RPC](guides/12_NodeAndDistributedErlang.md#rpc) 110 | 111 | 13. [**Differences From Erlang**](guides/13_DifferencesFromErlang.md) 112 | - [Overview](guides/13_DifferencesFromErlang.md#overview) 113 | - [Variables](guides/13_DifferencesFromErlang.md#variables) 114 | - [Delimiters](guides/13_DifferencesFromErlang.md#delimiters) 115 | - [Comments](guides/13_DifferencesFromErlang.md#comments) 116 | - [Functions](guides/13_DifferencesFromErlang.md#functions) 117 | - [Data Types](guides/13_DifferencesFromErlang.md#data-types) 118 | - [List Comprehensions](guides/13_DifferencesFromErlang.md#list-comprehensions) 119 | - [Expressions](guides/13_DifferencesFromErlang.md#expressions) 120 | - [Operators](guides/13_DifferencesFromErlang.md#operators) 121 | - [Modules](guides/13_DifferencesFromErlang.md#modules) 122 | 123 | ## [**FAQ**](FAQ.md) 124 | -------------------------------------------------------------------------------- /guides/09_DataTypesMapping.md: -------------------------------------------------------------------------------- 1 | # Data Types Mapping 2 | 3 | [ToC] 4 | 5 | ## Overview 6 | 7 | The Hamler Data Types are mapping to Erlang Data types at compile-time. The following table shows the overview of the mappings: 8 | 9 | | Hamler Data Type | Erlang Data Type | Mapping Description | 10 | | -------------------- | ----------------------- | --------------------------------- | 11 | | Atom(Symbol in Ruby) | atom() | | 12 | | Bool | boolean() | true -> true
false -> false | 13 | | Char | char() | | 14 | | Integer(Int) | integer() | Integer type | 15 | | Float(Double) | float() | Float type | 16 | | String | string() | | 17 | | Tuple | tuple() | | 18 | | List | list() | | 19 | | Map | map() | | 20 | | Record | map() | | 21 | | Binary | binary() \| bitstring() | | 22 | | Port | port() | Erlang Port | 23 | | Pid | pid() | Erlang Pid | 24 | | Reference(Ref) | reference() | Erlang Reference | 25 | 26 | ## Atoms Mapping 27 | 28 | **Atom** is a constant with name, which is also known as **Symbol** in other languages, such as Ruby. 29 | 30 | **Atoms** in Hamler are imported from Erlang, defined as a primitive type, but have a different syntax from Erlang. 31 | 32 | **Atoms** in Hamler start with a colon `:` 33 | 34 | ```hamler 35 | :ok 36 | :error 37 | :the_1st_Atom 38 | atom("node@127.0.0.1") 39 | ``` 40 | **Atoms** in Erlang: 41 | 42 | ```erlang 43 | ok 44 | error 45 | the_1st_Atom 46 | 'node@127.0.0.1' 47 | ``` 48 | 49 | ## Booleans Mapping 50 | 51 | The syntax of **Booleans** in Hamler is the same as Erlang. The difference is that **Boolean** is a primitive type in Hamler, while `true` and `false` are atoms in Erlang. 52 | 53 | **Booleans** in Hamler: 54 | 55 | ```hamler 56 | true 57 | false 58 | ``` 59 | 60 | **Booleans** in Erlang: 61 | 62 | ```hamler 63 | true 64 | false 65 | ``` 66 | 67 | ## Chars Mapping 68 | 69 | **Chars** in Hamler are also UTF-8 Unicode characters but with different syntax from Erlang. 70 | 71 | **Chars** in Hamler are enclosed in single quotes, which is similar to most programming languages. 72 | 73 | ```hamler 74 | 'a' 75 | 'b' 76 | 'の' 77 | ``` 78 | 79 | **Chars** in Erlang start with '$': 80 | 81 | ```hamler 82 | $a 83 | $b 84 | $の 85 | ``` 86 | 87 | ## Integers Mapping 88 | 89 | **Integers** in Hamler are the same as Erlang, with unlimited size. Hamler defines `Int` as an alias for `Integer`. 90 | 91 | Binary, octal, and hex integers in Hamler have a different syntax than Erlang. 92 | 93 | **Integers** in Hamler: 94 | 95 | ```hamler 96 | 1, 2, -10 97 | -- binary 98 | 0b101, 0B101 99 | -- octal 100 | 0o1, 0O1, 0o52, 0O752 101 | -- hex 102 | 0x1, 0X1, 0x2a, 0X2A, 0xff 103 | ``` 104 | 105 | **Integers** in Erlang: 106 | 107 | ```erlang 108 | 1, 2, -10 109 | -- binary 110 | 2#101, 2#10 111 | -- octal 112 | 8#1, 8#52, 8#752 113 | -- hex 114 | 16#01, 16#2a, 16#2A, 16#ff 115 | ``` 116 | 117 | ## Floats Mapping 118 | 119 | **Floats** in Hamler are the same as Erlang, which are also known as **Doubles** in other languages. 120 | 121 | **Floats** in Hamler and Erlang: 122 | 123 | ```erlang 124 | 1.0, 1.0e10 125 | 2.3 126 | 2.3e-3 127 | 0.0023 128 | ``` 129 | 130 | ## Strings Mapping 131 | 132 | **Strings** in both Hamler and Erlang are a list of UTF-8 characters. 133 | 134 | **Strings** in Hamler and Erlang: 135 | 136 | ```erlang 137 | "Hello, World!" 138 | "你好,世界" 139 | "ハロー、ワールド" 140 | ``` 141 | 142 | ## Tuples Mapping 143 | 144 | **Tuples** are defined as primitive data types in Hamler and compiled to Erlang tuples. 145 | 146 | The differences from Erlang are as below: 147 | 148 | - **Tuples** in Hamler are enclosed within parentheses, while **Tuples** in Erlang are enclosed in braces. 149 | 150 | - The maximum length of **Tuples** in Hamler is 7, while there is no limit in Erlang. 151 | 152 | **Tuples** in Hamler: 153 | 154 | ```hamler 155 | (1, "a", true) 156 | (1, "a") 157 | (:error, "Reason") 158 | 159 | -- fst, snd 160 | fst (1, 'a') :: Integer -- 1 161 | snd (1, 'a') :: Char -- 'a' 162 | ``` 163 | 164 | **Tuples** in Erlang: 165 | 166 | ```erlang 167 | {1, "a", true} 168 | {1, "a"} 169 | 170 | {error, "Reason"} 171 | ``` 172 | 173 | ## Lists Mapping 174 | 175 | **Lists** in Hamler are the same as in Erlang. 176 | 177 | **Lists** in Hamler: 178 | 179 | ```hamler 180 | {-- List --} 181 | [] -- empty list 182 | [1,2,3] -- Integer list 183 | 184 | [1|[2,3]] -- Cons 185 | [1|[2|[3|[]]]] -- Cons 186 | 187 | [x|_] = [1,2,3] -- List pattern 188 | [_|xs] = [1,2,3] -- List pattern 189 | [x|xs] -- Cons 190 | ``` 191 | 192 | **Lists** in Erlang: 193 | ```erlang 194 | %% List 195 | [] %% empty list 196 | [1,2,3] %% Integer list 197 | 198 | [1|[2,3]] %% Cons 199 | [1|[2|[3|[]]]] %% Cons 200 | 201 | [H|_] = [1,2,3] %% List pattern 202 | [_|T] = [1,2,3] %% List pattern 203 | [H|T] %% Cons 204 | ``` 205 | 206 | ## Enum, Range 207 | 208 | Hamler provides an enumeration or range syntax to help construct lists. 209 | 210 | ```hamler 211 | [1..10] --[1,2,3,4,5,6,7,8,9,10] 212 | 213 | [0, 5..100] -- [0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100] 214 | 215 | ['a'..'z'] --"abcdefghijklmnopqrstuvwxyz" 216 | ``` 217 | 218 | ## Maps Mapping 219 | 220 | The syntax of **Maps** in Hamler is the same as Erlang. The differences are listed below: 221 | 222 | - The keys of a Map must have the same type in Hamler; 223 | - The values of a Map must have the same type in Hamler; 224 | - The syntax `#{k := v}` is only used for map pattern matching. 225 | 226 | **Maps** in Hamler: 227 | 228 | ```hamler 229 | -- New map, values and keys must have the same type. 230 | m = #{:foo => "foo", :bar => "bar"} 231 | 232 | -- Pattern matching 233 | #{:foo := a, :bar := b} = m 234 | a :: String -- "foo" 235 | b :: String -- "bar" 236 | ``` 237 | 238 | **Maps** in Erlang: 239 | ```erlang 240 | %% Create a map 241 | M = #{foo => "foo", bar => "bar"} 242 | 243 | %% Pattern matching 244 | #{foo := A, bar := B} = M. 245 | A %% "foo" 246 | B %% "bar" 247 | ``` 248 | 249 | ## Records Mapping 250 | 251 | **Records** in Hamler are mapping to Erlang **Maps** at compile-time. 252 | 253 | **Records** in Hamler: 254 | 255 | ```hamler 256 | type Person = {name :: String, age :: Integer} 257 | john = {name = "John", age = 12} 258 | ``` 259 | 260 | Compiled to Erlang's Maps: 261 | ``` 262 | %% john 263 | #{age => 12,name => "John"} 264 | ``` 265 | 266 | ## Binaries Mapping 267 | 268 | **Binaries** in Hamler are imported from Erlang. The **Bit Syntax Expressions** in Erlang are defined as below: 269 | 270 | ```erlang 271 | <<>> 272 | <> 273 | 274 | Ei ::= Value 275 | | Value ":" Size 276 | | Value "/" TypeSpecifierList 277 | | Value ":" Size "/" TypeSpecifierList 278 | ``` 279 | 280 | The **Bit Syntax** in Hamler is a bit different from Erlang, that '/' is replaced with ':': 281 | 282 | ```hamler 283 | <<>> 284 | <> 285 | Ei ::= Value 286 | | Value ":" Size 287 | | Value ":" TypeSpecifierList 288 | | Value ":" Size ":" TypeSpecifierList 289 | ``` 290 | 291 | **Binaries** in Hamler: 292 | 293 | ```hamler 294 | <<127,0,0,1>> 295 | <<"ABC">> 296 | 297 | -- Binary Pattern Match 298 | <> = <<1,2>> 299 | <> = <<1,2>> 300 | ``` 301 | 302 | **Binaries** in Erlang: 303 | ```erlang 304 | <<127,0,0,1>> 305 | <<"ABC">> 306 | <<1:16,2:4,3:4>> 307 | 308 | -- Binary Pattern Match 309 | <> = <<1,0>> 310 | <> = <<1,2>> 311 | <> = <<1,2>> 312 | ``` 313 | 314 | ## Ports Mapping 315 | 316 | The **Port** data type in Hamler is foreign imported from Erlang. 317 | 318 | ## Pids Mapping 319 | 320 | The **Pid** data type in Hamler is foreign imported from Erlang. **Pid** in Erlang is a unique identifier of the Erlang lightweight process. 321 | 322 | ## References Mapping 323 | 324 | The **Reference** data type in Hamler is a foreign imported data type from Erlang. 325 | 326 | Create a **Reference** in Hamler: 327 | ```hamler 328 | import Data.Ref 329 | makeRef 330 | ``` 331 | 332 | ## User-defined data types Mapping 333 | 334 | The constructors of Sum/Product algebraic data types are mapping to tuples in Erlang at compile-time. 335 | 336 | Hamler: 337 | ```hamler 338 | -- Sum datatype 339 | data Color = Red | Green | Blue 340 | Red -- {'Red'} 341 | Green -- {'Green'} 342 | Blue -- {'Blue'} 343 | 344 | -- Product datatype 345 | data Pair = Pair Integer Integer 346 | Pair 3 4 -- {'Pair',3,4} 347 | 348 | -- Maybe 349 | data Maybe a = Just a | Nothing 350 | Nothing -- {'Nothing'} 351 | Just 5 -- {'Just',5} 352 | ``` 353 | 354 | Erlang: 355 | ```erlang 356 | {'Red'} %% Red 357 | {'Green'} %% Green 358 | {'Blue'} %% Blue 359 | 360 | {'Pair',3,4} %% Pair 3 4 361 | 362 | {'Nothing'} %% Nothing 363 | {'Just',5} %% Just 5 364 | ``` 365 | 366 | -------------------------------------------------------------------------------- /guides/11_OTPBehaviours.md: -------------------------------------------------------------------------------- 1 | # OTP Behaviours 2 | 3 | [ToC] 4 | 5 | ## Overview 6 | 7 | Hamler implements OTP Behaviours with Type Classes. 8 | 9 | ## GenServer 10 | 11 | ### Client-Server Model 12 | 13 | See: [Erlang gen_server Behaviour](https://erlang.org/doc/design_principles/gen_server_concepts.html) 14 | 15 | ![Client-server model](https://erlang.org/doc/design_principles/clientserver.gif) 16 | 17 | ### GenServer Typeclass 18 | 19 | ```haskell 20 | class GenServer req rep st | req -> rep, rep -> st, st -> req where 21 | handleCall :: HandleCall req rep st 22 | handleCast :: HandleCast req rep st 23 | ``` 24 | 25 | ### Server Example 26 | 27 | ```haskell 28 | module Demo.Server 29 | ( start 30 | , inc 31 | , dec 32 | , query 33 | ) where 34 | 35 | import Prelude 36 | import Control.Behaviour.GenServer 37 | ( class GenServer 38 | , HandleCall 39 | , HandleCast 40 | , Init 41 | , startLinkWith 42 | , initOk 43 | , call 44 | , cast 45 | , noReply 46 | , reply 47 | , shutdown 48 | ) 49 | import System.IO (println) 50 | 51 | data Request = Inc | Dec | Query 52 | data Reply = QueryResult Integer 53 | data State = State Integer 54 | 55 | name :: Atom 56 | name = :server 57 | 58 | start :: Process Pid 59 | start = startLinkWith name (init 20) 60 | 61 | ----------------------------------------------------------------------------- 62 | -- | Server API 63 | ----------------------------------------------------------------------------- 64 | 65 | inc :: Process () 66 | inc = cast name Inc 67 | 68 | dec :: Process () 69 | dec = cast name Dec 70 | 71 | query :: Process Integer 72 | query = do 73 | QueryResult i <- call name Query 74 | return i 75 | 76 | ----------------------------------------------------------------------------- 77 | -- | Server callbacks 78 | ----------------------------------------------------------------------------- 79 | 80 | instance GenServer Request Reply State where 81 | handleCall = handleCall 82 | handleCast = handleCast 83 | 84 | init :: Integer -> Init Request State 85 | init n = initOk (State n) 86 | 87 | handleCall :: HandleCall Request Reply State 88 | handleCall Query _from (State i) = do 89 | println "Call: Query" 90 | reply (QueryResult i) (State i) 91 | handleCall _req _from st = 92 | shutdown :badRequest st 93 | 94 | handleCast :: HandleCast Request Reply State 95 | handleCast Inc (State n) = do 96 | println "Cast: Inc" 97 | noReply $ State (n+1) 98 | handleCast Dec (State n) = do 99 | println "Cast: Dec" 100 | noReply $ State (n-1) 101 | handleCast _ st = noReply st 102 | ``` 103 | 104 | ### Start a Server process 105 | 106 | ```haskell 107 | -- | Start a standalone Server process. 108 | start :: forall req rep st. GenServer req rep st => (Init req st) -> Process Pid 109 | startWith :: forall req rep st. GenServer req rep st => Name -> (Init req st) -> Process Pid 110 | 111 | -- | Start a Server process as part of a supervision tree. 112 | startLink :: forall req rep st. GenServer req rep st => (Init req st) -> Process Pid 113 | startLinkWith :: forall req rep st. GenServer req rep st => Name -> (Init req st) -> Process Pid 114 | ``` 115 | 116 | ### Init callback 117 | 118 | ```haskell 119 | -- | Init Result 120 | data InitResult req st 121 | = InitOk st (Maybe (Action req)) 122 | -- ^ {ok, State} 123 | | InitIgnore 124 | -- ^ ignore 125 | | InitStop ExitReason 126 | -- ^ {stop, Reason} 127 | 128 | -- | Init callback 129 | type Init req st = Process (InitResult req st) 130 | ``` 131 | 132 | ### HandleCall and HandleCast 133 | 134 | ```haskell 135 | -- | HandleCall callback 136 | type HandleCall req rep st 137 | = req -> From -> st -> Process (Reply req rep st) 138 | 139 | -- | HandleCast callback 140 | type HandleCast req rep st 141 | = req -> st -> Process (Reply req rep st) 142 | ``` 143 | 144 | ### Client APIs 145 | 146 | ```haskell 147 | -- | Synchronous call to the server process. 148 | call :: forall req rep. Name -> req -> Process rep 149 | 150 | -- | Sends an asynchronous request to the server process. 151 | cast :: forall req. Name -> req -> Process () 152 | ``` 153 | 154 | ## GenStatem 155 | 156 | ### Event-Driven FSM 157 | 158 | See: [Erlang gen_statem Behaviour](https://erlang.org/doc/design_principles/statem.html) 159 | 160 | ``` 161 | State(S) x Event(E) -> Actions(A), State(S') 162 | ``` 163 | 164 | ### GenStatem Typeclass 165 | 166 | ```haskell 167 | class GenStatem e s d | e -> s, s -> d, d -> e where 168 | handleEvent :: HandleEvent e s d 169 | ``` 170 | 171 | ### CodeLock Example 172 | 173 | ```haskell 174 | module Demo.FSM.CodeLock 175 | ( name 176 | , start 177 | , push 178 | , stop 179 | ) where 180 | 181 | import Prelude 182 | 183 | import Control.Behaviour.GenStatem 184 | ( class GenStatem 185 | , Action(..) 186 | , EventType(..) 187 | , Init 188 | , OnEvent 189 | , initOk 190 | , handleWith 191 | , unhandled 192 | ) 193 | import Control.Behaviour.GenStatem as FSM 194 | 195 | data Event = Button Integer | Lock 196 | data State = Locked | Opened 197 | data Data = Data 198 | { code :: [Integer] 199 | , length :: Integer 200 | , buttons :: [Integer] 201 | } 202 | 203 | instance Eq State where 204 | eq Locked Locked = true 205 | eq Opened Opened = true 206 | eq _ _ = false 207 | 208 | instance GenStatem Event State Data where 209 | handleEvent = handleWith [(Locked, locked), (Opened, opened)] 210 | 211 | name :: Atom 212 | name = :code_lock 213 | 214 | start :: [Integer] -> Process Pid 215 | start code = FSM.startLinkWith name (init code) 216 | 217 | push :: Integer -> Process () 218 | push n = FSM.cast name (Button n) 219 | 220 | stop :: Process () 221 | stop = FSM.stop name 222 | 223 | init :: [Integer] -> Init Event State Data 224 | init code = initOk Locked d 225 | where d = Data $ { code = reverse code 226 | , length = length code 227 | , buttons = [] 228 | } 229 | 230 | locked :: OnEvent Event State Data 231 | locked Cast (Button n) (Data d) = 232 | let buttons = take d.length [n|d.buttons] 233 | in if buttons == d.code then 234 | let actions = [StateTimeout 1000 Lock] in 235 | FSM.nextWith Opened (Data d{buttons = []}) actions 236 | else FSM.keep (Data d{buttons = buttons}) 237 | 238 | locked t e d = unhandled t e Locked d 239 | 240 | opened :: OnEvent Event State Data 241 | opened Cast (Button _) d = FSM.keep d 242 | 243 | opened Timeout Lock d = do 244 | println "Timeout Lock" 245 | FSM.next Locked d 246 | 247 | opened t e d = unhandled t e Opened d 248 | ``` 249 | 250 | ### Start a FSM process 251 | 252 | ```haskell 253 | -- | Start a standalone FSM process 254 | start :: forall e s d. GenStatem e s d => (Init e s d) -> Process Pid 255 | startWith :: forall e s d. GenStatem e s d => Name -> (Init e s d) -> Process Pid 256 | 257 | -- | Start a FSM process as part of a supervision tree. 258 | startLink :: forall e s d. GenStatem e s d => (Init e s d) -> Process Pid 259 | startLinkWith :: forall e s d. GenStatem e s d => Name -> (Init e s d) -> Process Pid 260 | ``` 261 | 262 | ### Init callback 263 | 264 | ```haskell 265 | -- | Init Result 266 | data InitResult e s d 267 | = InitOk s d [Action e] 268 | -- ^ {ok, State, Actions} 269 | | InitIgnore 270 | -- ^ ignore 271 | | InitStop ExitReason 272 | -- ^ {stop, Reason} 273 | 274 | -- | Init Action 275 | type Init e s d = Process (InitResult e s d) 276 | ``` 277 | 278 | ### HandleEvent callback 279 | 280 | ```haskell 281 | -- | Event Type 282 | data EventType 283 | = Call From | Cast | Info 284 | -- ^ external event type 285 | | Timeout 286 | -- ^ timeout event type 287 | | Internal 288 | -- ^ internal 289 | 290 | -- | Statem Transition 291 | data Transition e s d 292 | = Keep d [Action e] 293 | | Next s d [Action e] 294 | | Repeat d [Action e] 295 | | Shutdown ExitReason d 296 | 297 | type HandleEvent e s d = EventType -> e -> s -> d -> Process (Transition e s d) 298 | 299 | -- | On Event 300 | type OnEvent e s d = EventType -> e -> d -> Process (Transition e s d) 301 | 302 | -- | Handle with state functions. 303 | handleWith :: forall e s d. [(s, OnEvent e s d)] -> HandleEvent e s d 304 | ``` 305 | 306 | ### Client APIs 307 | 308 | ``` 309 | call :: forall req rep. Name -> req -> Process rep 310 | 311 | cast :: forall msg. Name -> msg -> Process () 312 | ``` 313 | 314 | ## GenEvent 315 | 316 | ### Event Handling Principles 317 | 318 | See: [Erlang gen_event Behaviour](https://erlang.org/doc/design_principles/events.html) 319 | 320 | ### GenEvent Typeclass 321 | 322 | ```haskell 323 | class GenEvent e st | e -> st, st -> e where 324 | handleEvent :: HandleEvent e st 325 | ``` 326 | 327 | ### Event Manager Example 328 | 329 | ```haskell 330 | module Demo.Event 331 | ( Event(..) 332 | , start 333 | , notify 334 | ) where 335 | 336 | import Prelude 337 | 338 | import Control.Behaviour.GenEvent 339 | ( class GenEvent 340 | , Init 341 | , initOk 342 | , HandleEvent 343 | , startLinkWith 344 | ) 345 | import Control.Behaviour.GenEvent as E 346 | 347 | data Event = EventA | EventB 348 | data State = State [Event] 349 | 350 | instance GenEvent Event State where 351 | handleEvent = handleEvent 352 | 353 | name :: Atom 354 | name = :event 355 | 356 | start :: Process Pid 357 | start = startLinkWith name init 358 | 359 | notify :: Event -> Process () 360 | notify = E.notify name 361 | 362 | init :: Init State 363 | init = initOk (State []) 364 | 365 | handleEvent :: HandleEvent Event State 366 | handleEvent e (State events) = do 367 | println "Event" 368 | return $ State [e|events] 369 | ``` 370 | 371 | ### Start a Event Manager process 372 | 373 | ```haskell 374 | -- | Start a standalone Event Manager process. 375 | start :: forall e st. GenEvent e st => (Init st) -> Process Pid 376 | startWith :: forall e st. GenEvent e st => Name -> (Init st) -> Process Pid 377 | 378 | -- | Start a Event Manager process as part of a supervision tree. 379 | startLink :: forall e st. GenEvent e st => (Init st) -> Process Pid 380 | startLinkWith :: forall e st. GenEvent e st => Name -> (Init st) -> Process Pid 381 | ``` 382 | 383 | ### Init callback 384 | 385 | ```haskell 386 | data InitResult st 387 | = InitOk st 388 | | InitOkHib st 389 | | InitError ExitReason 390 | 391 | -- | Init callback 392 | type Init st = Process (InitResult st) 393 | ``` 394 | 395 | ### HandleEvent Callback 396 | 397 | ```haskell 398 | -- | HandleEvent callback 399 | type HandleEvent e st = e -> st -> Process st 400 | ``` 401 | 402 | ### Client APIs 403 | 404 | ```haskell 405 | notify :: forall e. Name -> e -> Process () 406 | 407 | syncNotify :: forall e. Name -> e -> Process () 408 | ``` 409 | 410 | ## Supervisor 411 | 412 | ### Supervision Tree 413 | 414 | See: [Erlang Supervisor Behaviour](https://erlang.org/doc/design_principles/sup_princ.html) 415 | 416 | ## Example 417 | 418 | ```haskell 419 | module Demo.Sup (start) where 420 | 421 | import Prelude 422 | 423 | import Demo.Event as Event 424 | import Demo.Server as Server 425 | import Demo.FSM.PushButton as FSM 426 | import Control.Behaviour.Supervisor 427 | ( Init 428 | , initOk 429 | , Strategy(..) 430 | , childSpec 431 | , startSupWith 432 | ) 433 | 434 | name :: Atom 435 | name = :sup 436 | 437 | start :: Process Pid 438 | start = startSupWith name init 439 | 440 | init :: Init 441 | init = initOk (OneForOne, 10, 100) 442 | [ childSpec "Demo.Event" Event.start 443 | , childSpec "Demo.Server" Server.start 444 | , childSpec "Demo.Statem" FSM.start 445 | ] 446 | 447 | ``` 448 | 449 | ### Start a Supervisor process 450 | 451 | ```haskell 452 | -- Start a supervisor process. 453 | startSup :: Init -> Process Pid 454 | 455 | -- Start a supervisor with name. 456 | startSupWith :: Name -> Init -> Process Pid 457 | ``` 458 | 459 | ### Init callback 460 | 461 | ```haskell 462 | type SupFlags = (Strategy, Intensity, Integer) 463 | 464 | -- | Init Result 465 | data InitResult 466 | = InitOk SupFlags [ChildSpec] 467 | -- ^ {ok, State} 468 | | InitIgnore 469 | -- ^ ignore 470 | 471 | -- | Init callback 472 | type Init = Process InitResult 473 | ``` 474 | 475 | ### Restart Strategy 476 | 477 | See: [Erlang Restart Strategy](https://erlang.org/doc/design_principles/sup_princ.html#restart-strategy) 478 | 479 | ```haskell 480 | data Strategy 481 | = OneForAll 482 | -- ^ Restart all child processes if one terminated. 483 | | OneForOne 484 | -- ^ Restart only the child processs terminated. 485 | | RestForOne 486 | -- ^ TODO: comment... 487 | | SimpleOneForOne 488 | -- ^ TODO: comment... 489 | ``` 490 | 491 | **OneForOne** 492 | 493 | **OneForAll** 494 | 495 | **OneForRest** 496 | 497 | **SimpleOneForOne** 498 | -------------------------------------------------------------------------------- /Cheatsheet.md: -------------------------------------------------------------------------------- 1 | # Hamler Cheatsheet 2 | 3 | **Hamler** is a haskell-style functional programming language running on Erlang VM. 4 | 5 | ![hamler-logo](https://www.hamler-lang.org/images/hamler@4x.png) 6 | 7 | [ToC] 8 | 9 | ## Hello world 10 | 11 | ```haskell 12 | module Main where 13 | 14 | import Prelude 15 | 16 | main :: IO () 17 | main = println "Hello, world!" 18 | ``` 19 | 20 | ## Hamler REPL 21 | 22 | ```haskell 23 | hamler repl 24 | > import Data.Map as Map 25 | > Map.empty 26 | #{} 27 | > 28 | ``` 29 | 30 | ## Comments 31 | 32 | ```haskell 33 | -- A single line comment 34 | {- Multi-line comments -} 35 | ``` 36 | 37 | ## Values, Types and Variables 38 | 39 | ```haskell 40 | -- Types, Values 41 | true :: Boolean 42 | false :: Boolean 43 | 2 :: Integer 44 | 1.0 :: Float 45 | 'a' :: Char 46 | "hello" :: String 47 | 48 | -- Variables Binding 49 | i = 1 50 | (a, b) = (1, 2) 51 | ``` 52 | 53 | ## Basic Types 54 | 55 | | Type | Values | Description | 56 | | ----------------- | ------------- | ----------------------------- | 57 | | Atom | :ok, :error | Erlang Atom type | 58 | | Boolean(Bool) | true \| false | Boolean type | 59 | | Char | 'c', 'x' | UTF-8 character | 60 | | String | "hello" | List of UTF-8 character | 61 | | Integer(Int) | 1, 2, -10 | Integer type | 62 | | Float(Double) | 3.14 | Float type | 63 | | List | | | 64 | | Tuple | (1, true) | | 65 | | Map | #{"k" => "v"} | Erlang Map | 66 | | Record | | | 67 | | Binary | <<1,2,3>> | Erlang Binary/Bitstring | 68 | | Pid | | Erlang Pid | 69 | | Port | | Erlang Port | 70 | | Reference(Ref) | | Erlang Reference | 71 | 72 | ### Booleans 73 | 74 | ```haskell 75 | true || false 76 | ``` 77 | 78 | ### Integers and Floats 79 | 80 | Two types of numeric literals: Integers and Floats. 81 | 82 | ```haskell 83 | -- Integer 84 | 1, 2, -10 85 | 86 | -- binary, octal, and hex literals 87 | 0x1, 0X1, 0x2a, 0X2A 88 | 0o1, 0O1, 0o52, 0O52 89 | 0b10, 0B10 90 | 91 | -- floats 92 | 1.0, 1e10 93 | 2.3 94 | 2.3e-3 95 | 0.0023 96 | ``` 97 | 98 | ### Atoms 99 | 100 | In Hamler, atoms start with ':', and correspond to Erlang atoms. 101 | 102 | ```hamler 103 | :atom, :ok, :error 104 | ``` 105 | 106 | ### Chars 107 | 108 | UTF-8 Unicode characters. 109 | 110 | ```haskell 111 | 'a', 'b', 'の' 112 | ``` 113 | 114 | ### Strings 115 | 116 | In Hamler, a string is a list of UTF-8 Unicode characters. 117 | 118 | ```haskell 119 | "Hello, World!" 120 | "你好,世界" 121 | "ハロー、ワールド" 122 | 123 | -- Escape Codes 124 | "\r\n ..." 125 | 126 | -- ++ to concat strings 127 | "Hello " ++ " World" 128 | 129 | -- TODO 130 | printf "foo %s" "bar" 131 | ``` 132 | 133 | ### Tuples 134 | 135 | A tuple is a sequence of values of different types. In Hamler, the maximum length of the tuple is 7. 136 | 137 | ```haskell 138 | (1, "a", true) 139 | (1, "a") 140 | 141 | -- fst, snd 142 | fst (1, 'a') :: Integer -- 1 143 | snd (1, 'a') :: Char -- 'a' 144 | ``` 145 | 146 | ### Lists 147 | 148 | A list is sequence of values of the same type: 149 | 150 | ```erlang 151 | {-- List --} 152 | [] -- empty list 153 | [1,2,3] -- Integer list 154 | 155 | [1|[2,3]] -- Cons 156 | [1|[2|[3|[]]]] -- Cons 157 | 158 | [x|_] = [1,2,3] -- List pattern 159 | [_|xs] = [1,2,3] -- List pattern 160 | [x|xs] -- Cons 161 | ``` 162 | 163 | ### Maps 164 | 165 | Erlang-style maps are available in Hamler: 166 | 167 | ```haskell 168 | -- New map; all keys must have the same type, and all values must have the same type. 169 | m = #{:foo => "foo", :bar => "bar"} 170 | 171 | -- Pattern matching 172 | #{:foo := a, :bar := b} = m 173 | a :: String -- "foo" 174 | b :: String -- "bar" 175 | 176 | -- get, put 177 | import Data.Map as Map 178 | m1 = Map.put :key "val" 179 | Map.get :foo m :: String -- "foo" 180 | Map.get :key m1 :: String -- "val" 181 | 182 | -- keys, values 183 | keys = Map.keys m -- [String] 184 | values = Map.values m -- [String] 185 | ``` 186 | 187 | ### Records 188 | 189 | ```haskell 190 | -- declare a Person record 191 | type Person = {name :: String, age :: Integer} 192 | 193 | -- create a Person record 194 | p = {name = "John", age = 12} 195 | 196 | -- update a Person record 197 | p1 = p{name = "Miles", age = 20} 198 | 199 | -- accessors 200 | name = p1.name :: String 201 | age = p1.age :: Integer 202 | ``` 203 | 204 | ### Binaries 205 | 206 | Binaries are imported from Erlang, which are raw byte strings. 207 | 208 | ```erlang 209 | -- Construct Binary 210 | <<127,0,0,1>> 211 | <<"ABC">> 212 | <<1:16,2:4,3:4>> 213 | 214 | -- Binary Pattern Match 215 | <> = <<1,0>> 216 | <> = <<1,2>> 217 | <> = <<1,2>> 218 | ``` 219 | 220 | ### Ports 221 | 222 | TODO: Erlang port identifier identifies an Erlang port. 223 | 224 | ### PIDs 225 | 226 | TODO: Erlang process identifier, pid, identifies a process. 227 | 228 | ### References 229 | 230 | TODO: Erlang reference 231 | 232 | ## User-defined Types 233 | 234 | Hamler supports algebraic data types (ADTs): 235 | 236 | ```haskell 237 | -- type synonym 238 | type Name = String 239 | "Miles" :: Name 240 | "Miles" :: String 241 | 242 | newtype UInt8 = UInt8 Integer 243 | 1 :: Integer 244 | UInt8 1 :: UInt8 245 | 246 | -- sum datatype 247 | data Color = Red | Green | Blue 248 | Blue :: Color 249 | 250 | -- product datatype 251 | data Pair = Pair Integer Integer 252 | Pair 3 4 :: Pair 253 | 254 | -- record product datatype 255 | data Person = Person { 256 | name :: String 257 | age :: Integer 258 | address :: String 259 | } 260 | Person {name = "Miles", age = 50, address = "NY"} :: Person 261 | 262 | -- generic datatype (maybe for example) 263 | data Maybe a = Just a | None 264 | data Result val err = Ok val | Error err 265 | 266 | -- recursive datatype 267 | data Tree = Leaf Integer | Node Tree Tree 268 | ``` 269 | 270 | ## Bindings 271 | 272 | ### let 273 | 274 | ```haskell 275 | let n = 1 + 2 276 | let (a, b) = (1, 2) 277 | ``` 278 | 279 | ### let .. in .. 280 | 281 | ```haskell 282 | z = let x = 3 283 | y = 2 * x 284 | in x * y 285 | ``` 286 | 287 | ### where 288 | 289 | ```haskell 290 | z = x * y 291 | where 292 | x = 3 293 | y = 5 294 | ``` 295 | 296 | ## Functions 297 | 298 | A function is a mapping from values of one type to values of another type. 299 | 300 | ### Function Definition and Application 301 | 302 | ```haskell 303 | add :: Integer -> Integer -> Integer 304 | add x y = x + y 305 | 306 | add 1 2 307 | ``` 308 | 309 | ### Polymorphic Functions 310 | 311 | ```haskell 312 | length :: forall a. [a] -> Integer 313 | 314 | -- example 315 | nats25 :: [Integer] 316 | nats25 = [0..25] 317 | 318 | letters :: [Char] 319 | letters = ['a'..'z'] 320 | 321 | n1 = length nats25 -- 26 322 | n2 = length letters -- 26 323 | 324 | zip :: forall a b. [a] -> [b] -> [(a,b)] 325 | ordL = zip nats25 letters 326 | 327 | -- [(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f'),(6,'g'),(7,'h'),(8,'i'),(9,'j'),(10,'k'),(11,'l'),(12,'m'),(13,'n'),(14,'o'),(15,'p'),(16,'q'),(17,'r'),(18,'s'),(19,'t'),(20,'u'),(21,'v'),(22,'w'),(23,'x'),(24,'y'),(25,'z')] 328 | ``` 329 | 330 | ### Currying 331 | 332 | ```haskell 333 | -- uncurried 334 | plus :: (Integer, Integer) -> Integer 335 | plus (x, y) = x + y 336 | 337 | -- sum is the curried version of plus 338 | sum :: Integer -> Integer -> Integer 339 | sum x y = x + y 340 | ``` 341 | 342 | ### Partial application 343 | 344 | ```haskell 345 | sum 1 2 :: Integer 346 | sum 1 (2 + 3) :: Integer 347 | 348 | add2 = sum 2 :: Integer -> Integer -- partially applied 349 | x = add2 3 :: Integer -- x = 5 350 | ``` 351 | 352 | ### High-Order Functions 353 | 354 | ```haskell 355 | apply :: forall a b. (a -> b) -> a -> b 356 | apply f x = f x 357 | ``` 358 | 359 | ### Recursive Function 360 | 361 | ```haskell 362 | fact n = if n == 0 then 1 else n * fact (n - 1) 363 | 364 | length [] = 0 365 | length [x|xs] = length xs + 1 366 | ``` 367 | 368 | ### Lambda (Anonymous Function) 369 | 370 | ```haskell 371 | multBy :: Integer -> Integer -> Integer 372 | multBy n = \m -> m * n 373 | 374 | mean :: Integer -> Integer -> Integer 375 | mean = \x y -> (x + y) `div` 2 -- f = (\x -> \y -> (x + y) `div` 2) 376 | ``` 377 | 378 | ### Function Pattern Matching 379 | 380 | ```haskell 381 | (x, y) = (1, 2) 382 | 383 | -- function declartion via pattern matching 384 | allEmpty [] = True 385 | allEmpty _ = False 386 | 387 | -- pattern matching stops when it finds the first match 388 | ``` 389 | 390 | ### Guarded Equations 391 | 392 | ```haskell 393 | abs n | n > 0 = n 394 | | otherwise = -n 395 | ``` 396 | 397 | ## Expressions 398 | 399 | ### if .. then .. else 400 | 401 | ```haskell 402 | -- Every `then` must have a corresponding `else` 403 | abs x = if x > 0 then x else -x 404 | 405 | -- Indentations 406 | sign x = 407 | if x > 0 408 | then print "pos" 409 | else if x < 0 410 | then print "neg" 411 | else print "zero" 412 | ``` 413 | 414 | ### case .. of 415 | 416 | ```haskell 417 | rgb = Red 418 | 419 | f = case rgb of 420 | Red -> "red" 421 | Green -> "green" 422 | Blue -> "blue" 423 | -- f has value "red" 424 | 425 | g = case rgb of Green -> "red"; _ -> "not red" 426 | -- g has value "not red" 427 | 428 | ``` 429 | 430 | ### List comprehensions 431 | 432 | A list comprehension consists of four types of elements: *generators*, *guards*, *local bindings*, and *targets*. 433 | 434 | ```haskell 435 | -- examples 436 | [x*2 | x <- [1,2,3]] -- [2,4,6] 437 | 438 | [x * x | x <- [1..10]] -- [1,4,9,16,25,36,49,64,81,100] 439 | 440 | -- multiple generators 441 | [(x,y) | x <- [1,2,3], y <- [4,5]] 442 | 443 | -- dependent generators 444 | [(x,y) | x <- [1..3], y <- [x..3]] 445 | 446 | -- conditions 447 | even i = 0 == i % 2 448 | [x | x <- [1..10], even x] 449 | ``` 450 | 451 | ### Enumerations, Range 452 | 453 | ```haskell 454 | [1..10] 455 | --[1,2,3,4,5,6,7,8,9,10] 456 | 457 | [0, 5..100] 458 | -- [0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100] 459 | 460 | ['a'..'z'] 461 | --"abcdefghijklmnopqrstuvwxyz" 462 | ``` 463 | 464 | ## Operators 465 | 466 | ### Arithmetic Operators 467 | 468 | | Operator | Name | Example | 469 | | -------- | ---------------- | ------- | 470 | | + | Add | | 471 | | - | Subtract | | 472 | | * | Multiply | | 473 | | / | Divide | | 474 | | % | Remain | | 475 | | div | Integer Division | div 7 3 | 476 | | rem | Remain | rem 7 3 | 477 | | | | | 478 | 479 | ### Logical Operators/Functions 480 | 481 | | Operator | Name | 482 | | -------- | ---- | 483 | | && | And | 484 | | \|\| | Or | 485 | | not | Not | 486 | | | | 487 | 488 | ### Relational Operators 489 | 490 | | Operator | Name | 491 | | -------- | ----------- | 492 | | == | Equal | 493 | | /= | Not Equal | 494 | | < | Less | 495 | | > | Great | 496 | | <= | Less Equal | 497 | | >= | Great Equal | 498 | 499 | ### Bit Operators 500 | 501 | | BitOp | Name | 502 | | ----- | --------------- | 503 | | band | Bit and | 504 | | bor | Bit or | 505 | | bnot | Bit not | 506 | | bxor | Bit xor | 507 | | bsl | Bit shift left | 508 | | bsr | Bit shift right | 509 | 510 | ## Modules 511 | 512 | A module is a compilation unit which exports types, functions, type classes and other modules. 513 | 514 | ### Module Declaration and Export 515 | 516 | The name of a module must start with a capital letter. 517 | 518 | ```haskell 519 | -- Declare a module and export all the types and functions 520 | module MyMod where 521 | 522 | -- Declare a module and export some types or functions 523 | module MyMod (Maybe(..), add) where 524 | 525 | data Maybe a = Just a | Nothing 526 | 527 | add :: Integer -> Integer -> Integer 528 | add x y = x + y 529 | ``` 530 | 531 | ### Main 532 | 533 | ```haskell 534 | -- Main 535 | module Main where 536 | 537 | import Prelude 538 | 539 | main = println "Hello World" 540 | ``` 541 | 542 | ### Import 543 | 544 | ```haskell 545 | import Data.List 546 | import Data.Map (keys, values) 547 | 548 | nth 1 [1..10] -- 1 549 | keys #{"key" => "val"} -- ["key"] 550 | values #{"key" => "val"} -- ["val"] 551 | 552 | -- Qualified Imports 553 | import Data.Set as Set 554 | import Data.Map as Map 555 | 556 | Map.get "foo" #{"foo" => "bar"} 557 | ``` 558 | 559 | ## Type classes 560 | 561 | TODO:... 562 | 563 | ## Functor, Applicative and Monad 564 | 565 | TODO:... 566 | 567 | ## Reserved Words 568 | 569 | ```haskell 570 | as after case class data do else false forall foreign hiding import if in infix infixl infixr instance kind let module newtype of receive then true type where 571 | ``` 572 | 573 | ## Holes 574 | 575 | Holes are widely used in the method of "Type-Driven Development". Holes stand for incomplete parts of programs. 576 | When you are not sure about how to define a function, try using holes to turn to REPL for help. 577 | To introduce a hole, give a name prefix with `?`. 578 | 579 | ``` 580 | > 42 + ?arg_0 581 | Error found: 582 | in module $REPL 583 | at :1:6 - 1:12 (line 1, column 6 - line 1, column 12) 584 | 585 | Hole 'arg_0' has the inferred type 586 | 587 | Integer 588 | 589 | You could substitute the hole with one of these values: 590 | 591 | $REPL.it :: Integer 592 | Data.Semiring.one :: forall a. Semiring a => a 593 | Data.Semiring.zero :: forall a. Semiring a => a 594 | ``` 595 | --------------------------------------------------------------------------------