Why Gren?

Gren is a programming language that helps you write simple and correct software.

What does that mean?

Simple

Gren measures simplicity by how many outcomes an operation can have. Take the following code as an example:

a + b

In some languages, this can mean a lot of different things. Some languages allow you to override the definition of +, which means it might execute an arbitrary function. For some languages, this statement can either append one string to another, or add two numbers together. Some languages might even try to convert a and b to be the same type, before executing the + operation.

In Gren, the above statement can only mean one thing: a and b are numbers, and the result is that of mathematical addition.

The fact that this statement can only mean one thing is what makes it simple. When reading the code you can be very certain what the result of this operation is, as long as it compiles.

Let's consider one more example, this one in JavaScript:

function doubleA(obj) {
    var a1 = obj.a;

    verify(obj);
    var a2 = obj.a;

    return a1 + a2;
}

Try to answer these questions:

  1. How many function calls do you see?
  2. Is the value of obj changed by any statement in this function?
  3. Does a1 equal a2?
  4. What type does this function return?
  5. Will this function return?

It might surprise you that, without knowing more of the surrounding context, you can't really answer any of these questions.

  1. JavaScript has a language feature called getters. This means that a statement like obj.a might actually call a function to compute a value. Without knowing how obj is defined, there's no way of knowing how many functions will be called.
  2. JavaScript allows mutation. The potential function call obj.a, and the actual function call verify(obj) might end up changing the obj value. You need to know how obj and verify is defined to be certain.
  3. Since obj can change, there's no way to know without knowing how obj and verify is defined. In languages that support threads, you also need to know if obj is accessible in any other thread.
  4. + works on both numbers and strings. So it probably returns either a number or a string.
  5. Maybe. Any function call can throw an exception.

Let's pretend the above code was written in Gren, could we answer the same questions with certainty then?

  1. Gren doesn't have getters, so the answer is 2 (verify and +).
  2. Gren doesn't have mutation, so the answer is no.
  3. Yes, because of (2).
  4. A number, since + only works on numbers.
  5. Gren doesn't support exceptions, so the answer is yes, if we ignore the possibility of infinite loops and running out of memory.

The simplicity of Gren makes it easier to reason about code. Even when the code in question was written by someone else. The value of simplicity grows along with the size of your code base.

Correct

There are certain constructs that Gren doesn't have, that are often the source of bugs in other languages. These things are:

  1. Null
  2. Exceptions
  3. Uncontrolled side-effects

What Gren does have is a flexible, although strict, type system which allows you represent these constructs in a way that let's the compiler help you avoid the most common bugs.

Instead of null, Gren lets you express the absence of a value by using what is known as a custom type:

type Maybe a
  = Just a
  | Nothing

This type represents a value which may, or may not, exist. Whenever you try to use this value, the compiler will force you to check if you have a Just or Nothing.

The same principle applies to exceptions. Representing an operation which may cause an error is represented by the type:

type Result err ok
  = Ok ok
  | Err err

If a function returns a Result value, the compiler will force you to handle both the success and the failure condition.

Consider for a moment what this means. Since Gren is statically typed, that means that whenever you see a function which doesn't return a Maybe or a Result type, you can be certain that you'll always end up with the promised return value.

The same concept applies to side-effects like performing HTTP calls or saving things to disk. A side effect has to be modelled by the type system, and this also means that you have greater insights into the sort of things a third-party package can do.

Conclusion

Gren has made a very specific set of trade-offs that makes it easy to locate and isolate bugs and side effects. These same trade-offs also make the language small in both syntax and concepts. This again reduces the necessary time investment to learn the language, and makes it easy for the compiler to provide detailed and helpful error messages.

These benefits comes at the cost of brevity. There's a chance that other programming languages will allow you to write less code.

It is our belief that as your program grows in complexity and scope, the trade-offs made by Gren make more and more sense.

Hello, world!

Getting a simple program to compile is a good way to verify that you've got everything setup correctly. Let's try to write a Gren program that outputs "Hello, world!" when opened up in a browser.

If you haven't already: install Gren.

Once you've setup the compiler correctly, it's time to initialize our project. We're going to assume that you've got a bash terminal setup.

Setting up your project

Start by creating a hello_world directory, and cd into it.

Every Gren project has a gren.json file. This file contains all the information that the compiler needs to compile your program. You can create such a file by running gren init.

~/W/g/hello_world> gren init
Hello! Gren projects always start with an gren.json file. I can create them!

Would you like me to create an gren.json file now? [Y/n]:
Retrieving versions for gren-lang/core... Ok!
Retrieving versions for gren-lang/browser... Ok!
Okay, I created it.

When run without any arguments, gren init creates a gren.json file in the current directory that defines a browser application. You can read more about the gren.json file in the appendix.

Writing your program

Create a src/Main.gren file and fill it with the following content:

module Main exposing (main)

import Html

main =
  Html.text "Hello, world!"

We create a new module, called Main and expose the main constant from it.

Then, we import the Html module. This module contains functions that allows us to define HTML elements. You can see everything that this module contains by reading it's documentation.

In our case, we just want to display some text. The text function is perfect for that. Our main constant, then, contains the value returned by Html.text "Hello, world!".

When this Gren program is run in a browser, whatever is returned by the main function is displayed on the page.

Compile your program using gren make src/Main.gren. This will produce a index.html file in your working directory which, when opened, displays Hello, world!.

You can now experiment by returning different HTML values from main. Compile and refresh the page to see what happens.

Getting started

In order to learn the language, it can be helpful to have a way of running arbitrary Gren expressions without having to setup and compile a full application.

Thankfully, there is such a tool. It's called a REPL (Read Eval Print Loop). It takes Gren expressions as input (read), compiles and run it (eval), then prints the result (print). It keeps doing this until you exit the program (loop).

Assuming you've already installed the Gren compiler, you can enter a REPL by running gren repl. It should look something like this:

> gren repl
Retrieving versions for gren-lang/core... Ok!
---- Gren 0.3.0 -----------------------------------------------------------------
Say :help for help and :exit to exit!
--------------------------------------------------------------------------------
>

For starters, try entering an expression like 1 + 2.

> 1 + 2
3 : number
>

You can see that the result of the expression 1 + 2 is 3, and that 3 is a number.

Of course, the REPL can also handle more complicated expressions. As you read the rest of this guide, try entering a few expressions into the REPL along the way.

Constants

You can attach names to values. Named values are called constants, because once defined those names can never refer to another value.

theAnswer = 42

aQuestion = "What is the answer?"

helpful = False

Gren supports several different kinds of constants. These are the primitive types:

  • Integers (Int): A whole number. Example: 42.
  • Floating point numbers (Float): An approximation of a fractional number. Example: 5.2.
  • Characters (Char): A single UTF-16 encoded character. Example: 'a'.
  • Strings (String): An array of UTF-16 encoded characters. Example: "test".
  • Booleans (Bool): Either True or False.

Functions

A function returns different values depending on its input. In Gren, a function will always return the same result if provided the same input.

sumOf first second =
    first + second

sumOfFiveAndTwo =
    sumOf 5 2

Here, sumOf is the name of the function, while first and second are the inputs to the function. The return value of sumOf, is the last computed expression. In this case, the only expression is first + second, the result of which becomes the returned value.

Functions can take an arbitrary number of arguments, but must return exactly one value.

Numbers

TODO

Arrays

You can group several values in an array.

numbers : Array Int
numbers =
    [ 1, 2, 3, 4, 5 ]

All values in an array must be of the same type. You cannot have an array of String and Int, for instance.

Strings

TODO

Records

You can also group different types of named values in a record.

twoSugars =
  { ingredient = "Sugar cube"
  , quantity = 2
  }

cupOfCoffee =
  { ingredient = "Cup of coffee"
  , quantity = 1
  }

sweetCoffeeCup : Array { ingredient : String, quantity : Int }
sweetCoffeeCup =
  [ cupOfCoffee, twoSugars ]

An interesting thing to note is that record types follow the shape of a record. Two records with the same names with the same associated types, are equal, even when defined in different modules.

The types can become rather painful to write, though, so Gren also supports type aliasing.

type alias QuantifiedIngredient =
  { ingredient : String
  , quantity : Int
  }

sweetCoffeeCup : Array QuantifiedIngredient
sweetCoffeeCup =
  [ cupOfCoffee, twoSugars ]

It can be useful to create a record which contains mostly the same values as some other record, but with a few modifications. Gren supports this through special syntax:

fourSugars =
  { twoSugars
    | quantity = 4
  }

The above example creates a new record, called fourSugars, which contains the same values as twoSugars, except that the quantity property has a value of 4 instead of 2.

Types

Gren is a statically typed language, which means that every constant and function are associated with a type, and the use of these types are checked by the compiler to be correct. If you have a function which is defined to accept to integers, the compiler will complain if you were to pass that function something other than two integers.

You might have noticed that you didn't need to specify types in the examples above. That's because Gren is usually smart enought to figure out the types without your help.

theAnswer : Int
theAnswer = 42

aQuestion : String
aQuestion = "What was the question again?"

helpful : Bool
helpful = False

sumOf : Int -> Int -> Int
sumOf first second =
    first + second

sumOfFiveAndTwo : Int
sumOfFiveAndTwo =
    sumOf 5 2

: can be read as has type. One way to read the first constant definition in the above example is: theAnswer has type Int. theAnswer equals 42.

For functions it get's a little bit more complicated. -> can be read as to. So: sumOf has type Int to Int to Int. sumOf first and second equals first + second.

When reading the type signature of a function, the last -> points to the return value of the function, while the types before represent the inputs.

If expressions

TODO

Custom Types

Sometimes it's helpful with values that can be in one of several states. This can be useful to represent values that may be absent, or operations which can succeed and fail, or cases where you'd typically use enums in other languages.

In Gren, this concept is known as custom types.

type Maybe a
    = Just a
    | Nothing

The type Maybe can be one of two things. Either it's Just a where a is a generic type, or it's Nothing in which case there is no associated data attached.

On its own, custom types aren't very helpful, but in combination with pattern matching they allow for some pretty interesting possibilities.

Pattern matching

When dealing with custom types, you likely want to do different things based on the actual value of the custom type. The case of expression provides this flexibility.

explainHeldItem : Maybe String -> String
explainHeldItem maybeItem =
    case maybeItem of
        Nothing ->
          "You're not holding anything"

        Just item ->
          "You're holding a " ++ item


holdingSword : String
holdingSword =
    explainHeldItem (Just "Sword")

You can use pattern matching on other things than just custom types. Like integers:

isZero : Int -> Bool
isZero num =
    case num of
        0 -> True
        _ -> False

Or even records:

combineIngredients : QuantifiedIngredient -> QuantifiedIngredient -> QuantifiedIngredient
combineIngredients left right =
    case { leftQty = left.quantity, rightQty = right.quantity } of
        { leftQty = 0 } ->
            right

        { rightQty = 0 } ->
            left

        _ ->
            { ingredient = left.ingredient ++ " and " ++ right.ingredient
            , quantity = left.quantity + right.quantity
            }

Modules

Every file containing Gren source code is considered a module.

A module is required to start with a module header, which at minimum defines the fully qualified module name and a list of exposed definitions. Being exposed means that the definition can be referenced by other modules.

Here's a minimal example of a module header:

module MyModule exposing (..)

Module name

The module name MyModule needs to coincide with the modules physical location on disk. In this case MyModule has to be at the top level of the src directory. If MyModule was located in src/Sub/MyModule.gren, then the project would have failed to compile.

When a module does exist within a sub-directory, like src/Some/Long/Path/For/Module.gren, then the module name should match the path, but with / replaced with ., like Some.Long.Path.For.Module.

Exposing

The exposing list is a comma seperated list of constants, functions and types that other modules can reference.

To expose everything from a module, you can use (..).

When exposing a custom type, you can either expose just the type, or the type along with its constructors. In the former case you'll add Type to the exposing list, in the latter you'll add Type(..) to the list. You cannot expose select constructors of a custom type, it's all or nothing.

Imports

If you want to reference something in another module, you'll need to import it.

import Some.Other.Module

This will allow you to reference values in Some.Other.Module by prefix the value with the module prefix.

Sometimes, as is the case in this example, the module name can be a bit long, in those cases you can specify a shorter alias for the module name:

import Some.Other.Module as Module

You can now prefix values with Module instead of Some.Other.Module.

Finally, you can opt in to not requiring specifying a prefix at all for commonly used values, by using an exposing statement:

import Some.Other.Module exposing (commonFunction)

You can now refer to commonFunction directly, as if it was defined in your module.

It's also possible to combine a module alias with an exposing list.

Comments

Lines starting with -- are ignored by the compiler, and are useful for describing something to human readers.

-- Nothing to see here

You can also use {- -} to have comments span multiple lines.

{- This comment
spans
multiple lines
-}

Comments can be used pretty much everywhere, as they're completely ignored by the compiler.

Documentation comments

There is a special kind of comments, called documentation comments, which are recognized by the compiler as being documentation for a module or a value.

These comments are enclosed within {-| -} and will be used to render documentation on packages.gren-lang.org.

{-| This is an approximation of pi
-}
pi = 3.14

Gren.json

Every Gren project is required to have a gren.json file. This file contains information about how to compile the project, and which platform to compile the project for.

There are two different types of project: applications and packages.

Depending on the type of project, the gren.json looks slightly different.

Applications

The gren.json file should look something like the following:

{
    "type": "application",
    "platform": "browser",
    "source-directories": [
        "src"
    ],
    "gren-version": "0.3.0",
    "dependencies": {
        "direct": {
            "gren-lang/browser": "3.0.0",
            "gren-lang/core": "4.0.0"
        },
        "indirect": {
            "gren-lang/url": "3.0.0"
        }
    }
}

Let's explain this property by property:

  • type: This tells the compiler that we're attempting to compile an application.
  • platform: Which platform are we expecting to run our application on? Can either be browser or node.
  • source-directories: This lists every sub-folder that the compiler should look for Gren source files in. This is usually fine as-is.
  • gren-version: Which version of the compiler is this application compatible with. If you're using an unsupported compiler, it will refuse to compile.
  • dependencies: Lists the packages that your application depends on. Direct dependencies are those which you application make direct use of, while indirect dependencies are required by your direct dependencies. The reason that both types of dependencies are listed in your gren.json file, is to make sure we always retrieve the same version of a given dependency. Each package name resolves to a github author/project name. Versions need to be formatted according to the semver specification, and must target a concrete version (no ranges).

Packages

The gren.json file for packages should look something like this:

{
  "type": "package",
  "platform": "common",
  "name": "yarl/stuff",
  "summary": "Yarl's reusable Gren code",
  "license": "BSD-3-Clause",
  "version": "1.0.0",
  "gren-version": "0.3.0 <= v < 0.4.0",
  "exposed-modules": {
    "Primitives": ["ModuleOne", "ModuleTwo"]
  },
  "dependencies": {
    "gren-lang/core": "3.0.0 <= v < 4.0.0"
  }
}

Let's explain this property by property:

  • type: This tells the compiler that we're attempting to compile a package. Code that can be reused in other packages and applications.
  • platform: Which platform is this package compatible with? Can either be browser,node or common which is to say it should work on any platform.
  • name: The name of the package. This should match the author/project path on Github. Currently, only Github is supported.
  • summary: A brief (80 characters maximum) summary of what your project does.
  • license: Specifies how your code is licensed.
  • version: The current semantic version of the package.
  • gren-version: Which version range of the compiler is this package compatible with.
  • exposed-modules: Specifies the modules that are importable in other projects. Can be a list of module names or, as is the case here, an object that categorize the exposed modules. The object format is relevant when generating documentation.
  • dependencies: Other packages that this package depends on. Notice that packages doesn't have references to indirect dependencies, and that versions are specified in ranges instead of being specific. When compiling your package directly, the lowest specified version will be selected. When compiled as part of another package or application, the lowest compatible version will be selected.

gren init

The compiler includes a command for generating gren.json files for new projects, to simplify setup.

To generate:

  • browser-based application: gren init
  • browser-based package: gren init --package
  • any application: gren init --platform <browser|node>
  • any package: gren init --package --platform <common|browser|node>

Frequently Asked Questions

Why is the language called Gren?

Gren is a norwegian word, meaning branch. This pays homage to both of Gren's origins: Norway and Elm.

Why is Gren's logo a bird?

The bird is a robin, which happens to be the name of Gren's founder. The robin is placed within the G, which is meant to symbolize that it is sitting on a G(ren), which is the norwegian word for branch.

What is the relationship between Gren and Elm?

Gren started as a fork of Elm. This is mostly considered to be an implementation detail, a way to speed up initial development.

It's not a goal of Gren to replace, or stay compatible in any way with, Elm.

What are the differences between Gren and Elm?

As of Gren 0.3.0, the main differences is that Gren has:

  • A git-based package manager. It's slower, but has access to any github repo that you have, even private ones.
  • The default sequential data structure is an immutable array, not a linked list.
  • Extended support for pattern matching on records.
  • Any expression that returns a record can be used for record updates.
  • Multiline strings trim leading whitespace on each line.
  • Supports running on NodeJS.
  • No tuples.
  • No automatic constructors for type aliased records.
  • No GLSL syntax.
  • No reactor.
  • Sourcemap support for native integration with the JS debugger.