In this part of the article we’re going to write our own library using . If you haven’t read yet, it’s strongly advised. It covers the basics of starting a new and an existing project with compiler. Elmchemy part one integrating Elmchemy During this tutorial we’ll learn how to: Define type aliases Define union types Use aliases and tagged unions as functions Pattern match on union types Use operators as functions and define your own custom ones Import types and type aliases from other modules So imagine we’re writing a game. An amazingly innovative game. A game no-one has ever made before. With characters, levels, stats, and items kind of game. It is set in sci-fi-ish word so we can have crossbows, rifles, crowbars, blasters and what-not. Because we’re creating a block-buster and project managers rarely happen to have inconceivable deadline expectations, we were assigned a single task: our job is to create a module responsible for our main character — .We’re a start-up and our salary is roughly 5 hundred bucks a month, so we were given the opportunity to plan out the features ourselves (Product manager would say it’s not what he wanted anyway). Gordon Freemonad We’re one lazy programmer and we’ll use a project created in . If you don’t have it, then you already failed. There goes your equity. As a first step we’ll create several scenarios testing unimplemented features, and then we’ll start thinking on how to implement them (look it up. It’s called TDD and it’s closest to gaming at work you can get without getting fired). Testing suite will be implemented in Elixir’s ExUnit exactly like in the previous part of the tutorial, everything else will be coded using Elmchemy only. part one Enough talking. Time to start coding. Preparation *This article was written using Elmchemy 0.3.31. Make sure to have a version that is above 0.3.31 but no higher than 0.4* Due to your wage and non-negotiable full-time amount of hours a week, you suffer from World Of Warcraft withdrawal. A lack of your both most hated and beloved game results in a pretty bold statement: . Every game character has to have stats Let’s write a test that will check that new character has them.If you followed previous part your project structure should look like this: Create a new file called inside directory and start with a boilerplate: character_test.exs test test/character_test.exs - Ignore the error on `use Elmchemy`. Our plugin just can’t see dependencies that are installed as mix archives Now what our character should have? Definitely a name and a surname. Having some gender would be nice too. Age is overrated so let’s leave that out. Not much but might be enough for our MVP. test/character_test.exs Cool. Next thing is we want him to have basic stats. Strength for damage, intelligence for weapon requirements and vitality for health should be enough for our MVP. We don’t yet know what will be the default values so let’s just check if the stats exists and are integers. character_test.exs We also check if we are able to set a stat for our character, using function. set_stat/3 Stats would be nothing if they didn’t provide some benefit for having them: Vitality boosts our health presented as {current_hp, max_hp} tuple: test/character_test.exs — We check that max hp increased, and also that our current hp adjusted itself accordingly In our test we create a new Gordon and clone two copies of him. One beefed up with 10 vitality, and the other who’s a programmer like us - with 0. Then we compare their health points and expect the former to have more of them.In the last line we make sure that boosting Gordon’s max health, also raises his base health accordingly. *Please note that we put the target of our function as last parameter, rather then the first one. That’s because in curried environment for pipes to work, we need the have the piping target as last argument — and that’s Elm’s and Elmchemy’s standard* Intelligence allows us to equip more advanced weapons: test/character_test.exs — We create two Gordons, a weapon with 9 intelligence requirement, Here we create a new character and a weapon with level 9 and 100 damage.Then we get two clones of Gordon: - one with Intelligence - and the other one with .We ran function on both of them, and expect it to fail on the character with intelligence, but succeed on one with 10 0 equip 0 10 At the end we make sure that the smarter clone of Gordon has a weapon in his arm. Please notice that we wrap it in single tuple , because that’s how Elmchemy represents type. With being and being {weapon} [Maybe](http://package.elm-lang.org/packages/elm-lang/core/latest/Maybe) {value} Just value nil Nothing. Implementation Test #1 — Character name, surname and gender Feature 1— Type aliases Now that we have our tests we can start implementing our character!For our schema we’re going to use a . It allows us to have a common name for any other type. We’re going to use it to alias a struct. Which Elmchemy represents as a map with atoms as keys. type alias Create a file with our type alias declaration. elm/Character.elm elm/Character.elm : If the type we’re aliasing is a struct or a tuple, we can use the alias as a function to create an instance of it with each argument being a each subsequent value in our type. f.i Type Alias Tip Character name surname gender health We declare our Character to have a name and a surname, which are strings.A gender of type which is a type we didn’t declare yet, and health as tuple, where the first one is current health, and the latter is max health. Gender Feature 2— Union Types Whenever we wan’t something to be matched on, we want a custom type.In Elmchemy are so called which basically means, the first symbol in each type declaration is a ‘tag’ that tells us what type the value represents. Union types in Elmchemy are represented as atoms in case of a single tag, and a tuple starting with an atom in case of tags wrapping one or more type.That’s how we’re going to declare our gender types ‘Tagged unions’ elm/Character.elm — We declare that gender can either be an atom :male, :female or :other Feature 3— Type Aliases as functions Now we can declare a function that returns a new character based on it’s parameters. new elm/Character.elm — function returning our Character type alias intance We take 3 parameters, which are name and surname as strings and a gender as our newly created union type. Then we pass the arguments to Character type as a function in the order we defined the fields.We also pass the default argument of health being 100 on 100 max. Gender If we run in our terminal right now we should have our first test passing. 3 to go! mix test Test #2 — Character stats Time to add stats. Let’s recall our test case character_test.exs First we need to define stats for our character type. And also define the stats structure: When we save, our compiler should nag us, that our function is no longer relevant to our type. new/3 Lets update it to contain default stats all being of value 0 Feature 4 — case statement on union types and record update syntax We need a type of a stat to match on Now we need to declare a function that takes a stat, value and character, and updates the stat to the value we want. **Did you know?**You can define type aliases using record update syntax. means any structure that has a field of type .You can then create types deriving from it like so: But remember, that way you sacrifice the short syntax for instantiating type aliases and have to type the entire struct by hand. type alias Namable a = { a | name : String} name String type alias Cat = Namable { lactoseIntolerance : Bool } ``type alias Dog = Namable { catIntolerance : Int } Great. That’s another test down! Test #3 — Boosting vitality test/character_test.exs — We check that max hp increased, and also that our current hp adjusted itself accordingly Now we need to add the functionality of changing health when setting a vitality stat. Feature 5— Operators as functions and custom operators Because our HP is a tuple we want to use on it. But for the sake of code tidiness we’re going to define an operator for us to use that as infix operator. Tuple.map We could use any operator i like, but for the sake of the shape I chose for the left tuple element and for the right one. You can experiment with what works best for you. <$ $> There is plenty of built in operators to make your life easier. You can use and to pipe function results, and to compose functions. There even is a comma operator that creates tuples for you. is equivalent to to and so on.Every operator is still a function so we can pass them to other functions to make our code much more expressive.All it takes to implement a zip of two lists is just to write Did you know? |> <| << >> (,) a b (a, b) (,,) a b c (a, b, c) List.map2 (,) listA listB Great. Now we can add the health change to the branch of our case. Vitality setStat We use to add a difference of current vitality and a new vitality value multiplied by 10.Then we use to set it to base 100 plus 10 times the vitality value.Since we need to pass it a function in the first case we give it a function and in the second we give it which basically returns the same thing (Basically it means the same as )If we didn’t use our operator the code would look as follows <$ $> (+) always always \_ -> (100 + 10 * value) character.health|> Tuple.mapFirst ((+) ((value - character.stats.vitality) * 10))|> Tuple.mapSecond (always (100 + 10 * value)) By now we should be with only one test failing left. Test #4 — Equipping a weapon when we’re intelligent enough test/character_test.exs - a weapon with 9 intelligence requirement, So we need a function, that either can or cannot equip a weapon. To do that we’re going to use type, that have a value of either or , which directly translates to or . Result a b Err a Ok b {:ok, a} {:error, b} Please notice the difference of Err translating to instead of . That’s one of exceptions in Elmchemy to keep Elixir and Elm interoperable without a consistency sacrifice :error :err But before we do that, we need to implement a Weapon type in general. To do that we’re create a new file, and learn to import and use remote types. Feature 6 — Union types and Type Aliases imported from other modules Let’s create a new file and add a function that would create a weapon for us elm/Weapon.elm new elm/Weapon.elm — weapon type definition *Please note that we create a _new_ function only for the sake of usage inside our Elixir code. The _Weapon_ type alias is a factory function itself when used inside Elmchemy’s scope. _Character_ factory function ( _Character.new_ ) was different because we specified some default values for it* Now that we have our type we can implement our function, but first we need to add an import on the top of our file, we use because the first one is the name of the module, and the latter of the type alias we want to import. Weapon equip Character.elm import Weapon exposing (Weapon) Also our character is right now armless. Let’s add it an arm, of type . Like we decided earlier we want to use type, because our character can either have something in his hand or have nothing at all.Let’s add an arm to our type with Maybe Weapon Maybe Character **Did you know?**There is a shorthand syntax to access a field in a struct as a function.By writing you can have a function that will fetch of a record. It’s equivalent to For example: .field field \a -> a.field arsenal : List Character -> List Weapon arsenal squad = List.map .arm _squad_ We need to add a default value for to our function too. arm Character.new elm/Character.elm Now that we have the type imported from the other file and an arm for our character we can go about our weapon equipping implementation: elm/Character.elm That’s it! If we run the tests now, we should see all 4 tests green. If you skipped some parts you can see the entire project under this repository: https://github.com/wende/elmchemy-article-example This is the end of part twoIn part three we will focus on calling Elixir code from Elmchemy and writing your own Native modules. In case of any questions regarding the project I’ll gladly answer in the comments section. Announcement: Elmchemy is undergoing a name change and is soon to be called “Elchemy” (without an “m”) <<< — Part One — Part Three >>>