- Bootstrap Example
- Inline Documentation
- Package Structure
- CLI Utilities
- Runtime Integration
- Core Primitives
- Data Structures
- Function Definitions
- Custom Types
- Aliasing Types
- Type Signatures
- Expression Operators
- Branching Logic
- JavaScript Interop
- functional paradigm enforcement
- compile-time type checking
- zero runtime crashes
- rendering performance exceeds competitors
- integrated dependency manager
- compiler toolchain included
- seamless JS/CSS/HTML integration
- minimal syntax overhead
- frontend development enjoyable again
File Bootstrap.elm:
import Html exposing (h1, text)
import Html.Attributes exposing (id)
-- Minimal working example
main =
h1 [id "bootstrap"] [text "Hello World!"]-- Single-line annotation
{-
Multiline
annotation block
-}Documentation for API generation
-- Export all module contents
module ProjectModule exposing (..)
-- Selective entity exports
module ProjectModule exposing (CustomType, staticValue)
-- Union type variant control
module ProjectModule exposing
( ErrorType(Unauthorized, ServiceDown)
, DataType(..)
)
type ErrorType
= Unauthorized String
| ServiceDown String
| NotAvailable String-- namespace imports
import String -- String.toUpper, String.repeat
import String as Str -- Str.toUpper, Str.repeat
-- direct imports
import ProjectModule exposing (..) -- ErrorType, DataType
import ProjectModule exposing ( ErrorType ) -- ErrorType
import ProjectModule exposing ( ErrorType(..) ) -- ErrorType, Unauthorized, ServiceDown
import ProjectModule exposing ( ErrorType(Unauthorized) ) -- ErrorType, Unauthorizedelm repl / elm-repl
Load dependencies
> import ListInspect signatures
> List.map
<function> : (a -> b) -> List a -> List b
> (++)
<function> : appendable -> appendable -> appendableEvaluate expressions
> 1 + 1
2 : numberMultiline with backslash \
> fn a b = \
| a + b
<function> : number -> number -> number
elm make / elm-make
# Standard build
elm make Bootstrap.elm -> index.html
# Named output
$ elm make Bootstrap.elm --output bootstrap.js
# Multi-file compilation
$ elm make Bootstrap.elm ProjectModule.elm --output bundle.js
# Verbose mode
$ elm make Bootstrap.elm --warn
# HTML generation
$ elm make Bootstrap.elm --output app.htmlelm package / elm-package
Automatic elm-package.json updates during install.
# Add dependency
$ elm-package install evancz/elm-html
# Version pinning
$ elm-package install evancz/elm-html 1.0.0
# Compare releases
$ elm-package diff evancz/virtual-dom 2.0.0 2.1.0
Comparing evancz/virtual-dom 2.0.0 to 2.1.0...
This is a MINOR change.
------ Changes to module VirtualDom - MINOR ------
Added:
attributeNS : String -> String -> String -> VirtualDom.PropertyPublishing requires complete documentation coverage.
module ApiDocumentation exposing
( CustomType
, staticValue
, helperFunction
)
{-| Top-level module description
# Primary section header
@docs CustomType, staticValue
# Utility Functions
@docs helperFunction
-}
import Random exposing (int)
{-| Type documentation block -}
type CustomType = Bool
{-|-}
-- Minimal doc comment
staticValue : Int
staticValue = 1 + 1
{-| Extended function description -}
helperFunction : Generator Int
helperFunction =
int 0 64
{-| Unexported values don't require doc comments -}
-- Standard comment syntax acceptable
privateValue =
"No documentation needed"- Doc comments:
{-|opening,-}closing - Module docs: after module declaration, before imports
- Section grouping via
@docs <identifiers>with Markdown formatting - All exported entities require doc comments
Add README.md (required for publishing)
Initial version: 1.0.0
Semantic versioning: MAJOR.MINOR.PATCH
PATCH- no API changes, safe updatesMINOR- additive changes only, backward compatibleMAJOR- breaking changes, removals or modifications
elm-package.json configuration
source-directories- source lookup paths within workspaceexposed-modules- public API surface after publishing
# elm-package.json
"source-directories": [
".",
"DirOne",
"DirTwo"
]
"exposed-modules": [
"DirOne",
"PublicModule",
"CoreModule"
]
├── DirOne
│ └── DirOne.elm # Compiled + exposed
├── DirTwo
│ └── DirTwo.elm # Compiled, not exposed
├── DirThree
│ └── DirThree.elm # Ignored by compiler
├── README.md
├── elm-package.json
├── PublicModule.elm # Compiled + exposed
└── CoreModule.elm # Compiled + exposedInitial release
$ git tag -a 1.0.0 -m "initial version"
$ git push --tags
$ elm-package publishVersion bump
$ elm-package bump
$ git tag -a 1.0.1 -m "patch update"
$ git push --tags
$ elm-package publishFullscreen mode
elm-make Bootstrap.elm -> elm.js
<script type="text/javascript" src="elm.js"></script>
<script type="text/javascript">
Elm.Main.fullscreen();
</script>Targeted embedding
<script type="text/javascript" src="elm.js"></script>
<script type="text/javascript">
var container = document.getElementById('elm-container');
Elm.Main.embed(container);
</script>Headless execution
Elm.Main.worker();Int and Float, generic number encompasses both:
> 1
1 : number
> 2.0
2 : Float
> truncate 0.1
0 : Int
> truncate 1
1 : IntChar for single characters, String for sequences
> 'a'
'a' : Char
> "Hello"
"Hello" : StringMultiline strings
"""
Line one
Line two
"""Character literals require single quotes
> 'ab'
-- SYNTAX PROBLEM --
> "ab"
"ab" : String> True
True : Bool
> False
False : Boolcomparable - ints, floats, chars, strings, lists, tuples
appendable - strings, lists, text
Generic types: a, b, c accept any value including functions
Immutability enforced across all data structures.
list contains homogeneous comma-separated values in brackets:
> []
[] : List a
> [1,2,3]
[1,2,3] : List number
> ["a", "b", "c"]
["a","b","c"] : List StringConstruction methods
> List.range 1 4
> [1,2,3,4]
> 1 :: [2,3,4]
> 1 :: 2 :: 3 :: 4 :: []Tuples group 2-9 heterogeneous expressions. Type signature reflects arity and component types.
> (1, "2", True)
(1,"2",True) : ( number, String, Bool )Comma as prefix function
> (,,,) 1 True 'a' []
(1,True,'a',[]) : ( number, Bool, Char, List a )Destructuring syntax
(x, y) = (1, 2)
> x
1 : numberrecord structure similar to JS objects
configuration =
{ theme = "Dark",
version = 2,
enabled = True
}Property access
> configuration.theme
"Dark" : String
> .theme configuration
"Dark" : StringImmutable updates
> updated = { configuration | theme = "Light", version = 3, enabled = False }
> configuration.theme
"Dark" : String
> updated.theme
"Light" : StringDestructuring records
{ theme, version, enabled } = configuration
> theme
"Dark" : StringStandard library includes:
Basic syntax
-- identifier | parameters = implementation
add a b = a + b
-- tuple parameter grouping
add (a, b) = a + bDefault currying behavior.
Multi-argument functions are chained single-argument functions:
-- Equivalent expressions
myFunction arg1 arg2
((myFunction arg1) arg2)
-- Partial application example
> subtract x y = (-) x y
<function> : number -> number -> number
> subtract5 = subtract 5
<function> : number -> number
> subtract5 20
15 : numberAnonymous function syntax
-- (\parameters -> implementation)
-- parenthesized, backslash prefix
(\n -> n < 0)
(\x y -> x * y)Prefix applies operators as standard functions via parentheses.
-- Standard infix
> "abc" ++ "def"
"abcdef" : String
-- Prefix application
> (++) "abc" "def"
"abcdef" : StringUnion types define custom discriminated unions.
Values match one variant from the definition. Pairs naturally with pattern matching.
type Direction = North | South | East | WestTagged variants with associated data
type Direction
= North Int
| South Int
| East Bool
| Coordinates (Float, Float)
-- Function application
navigate ( Coordinates (45.7, 67.5) )Parameterized union types
type Entity a
= FirstName String
| LastName String
| Age Int
| Metadata aMaybe handles nullability, optional parameters, error scenarios.
-- Import Maybe
import Maybe exposing ( Maybe(..) )
-- Generic optional wrapper
type Maybe a = Just a | NothingType signature documents optional return:
validateId : Int -> Maybe Int
validateId id =
if id >= 0 then
Just id
else
Nothingtype alias creates named type synonyms
type alias Username = String
type alias Birthdate = String
type alias UserRecord = { username: Username, birthdate: Birthdate }Alias usage in annotations
userRecord : UserRecord
userRecord =
{ username = "alice", birthdate = "15/03/1995" }Aliases equivalent to original types
type alias Username = String
username : Username
username =
"alice"
alternateUsername : String
alternateUsername =
"alice"
-- True
username == alternateUsernameAutomatic type inference for most declarations.
-- identifier : arg1Type -> arg2Type -> returnType
operation : Int -> List -> IntGeneric signatures: function accepting a returning b, transforming List a to List b
map: (a -> b) -> List a -> List bRecord field pattern matching
-- Requires fields x and y
scale {x,y} =
x * yRecord annotations
position : { x : Float, y : Float }
position =
{ x = 0,
y = 0
}Operators are binary functions.
| Symbol | Purpose | Signature |
|---|---|---|
+ |
addition | number -> number -> number |
- |
subtraction | number -> number -> number |
* |
multiplication | number -> number -> number |
/ |
float division | Float -> Float -> Float |
// |
integer division | Int -> Int -> Int |
^ |
power | number -> number -> number |
% |
remainder | Int -> Int -> Int |
| Symbol | Purpose | Signature |
|---|---|---|
and |
AND operation | Int -> Int -> Int |
or |
OR operation | Int -> Int -> Int |
xor |
XOR operation | Int -> Int -> Int |
| Symbol | Purpose | Signature |
|---|---|---|
== |
equality | comparable -> comparable -> Bool |
/= |
inequality | comparable -> comparable -> Bool |
< |
less than | comparable -> comparable -> Bool |
<= |
less or equal | comparable -> comparable -> Bool |
> |
greater than | comparable -> comparable -> Bool |
>= |
greater or equal | comparable -> comparable -> Bool |
| Symbol | Purpose | Signature |
|---|---|---|
&& |
conjunction | Bool -> Bool -> Bool |
|| |
disjunction | Bool -> Bool -> Bool |
not |
negation | Bool -> Bool |
| Symbol | Purpose | Signature |
|---|---|---|
<| |
backward application f <| x == f x |
(a -> b) -> a -> b |
|> |
forward application x |> f == f x |
a -> (a -> b) -> b |
<< |
right-to-left composition | (b -> c) -> (a -> b) -> a -> c |
>> |
left-to-right composition | (a -> b) -> (b -> c) -> a -> c |
| Symbol | Purpose | Signature |
|---|---|---|
++ |
concatenation | appendable -> appendable -> appendable |
:: |
list prepend | a -> List a -> List a |
as |
value aliasing (x, y) as t == t = (x, y) |
a -> a |
Branch types must unify.
if a < 1 then
"Zero"
else
"Nonzero"
-- Chained conditions
if y > 0 then
"Positive"
else if x /= 0 then
"Nonzero"
else
"Zero"Type coercion not supported.
Conditions must be strictly boolean.
> if 1 then "invalid" else "also invalid"
- TYPE MISMATCH --Case expression matches values against patterns
type Account
= Active
| Suspended
handleAccount status =
case status of
Active ->
-- activate logic
Suspended ->
-- suspend logicTagged union destructuring
type Account
= Active Int
| Suspended (Int, String)
handleAccount status =
case status of
Active userId ->
-- process userId
Suspended details ->
-- handle details
handleAccount ( Active 42 )
handleAccount ( Suspended (0, "inactive") )let defines local bindings.
let
x = 3 * 8
y = 4 ^ 2
in
x + yExpression simplification
let
validUsers = List.filter (\u -> u.status /= 0) model.users
in
{ model | users = validUsers }Bidirectional communication mechanism.
-- port declaration
port module Main exposing (..)
-- define receiver
port inboundPort : (String -> msg) -> Sub msgvar app = Elm.Main.embed(container);
// send data
app.ports.inboundPort.send("Data from JS");port outboundPort : String -> Cmd msgfunction handleData(data) {
console.log(data);
}
// listen for events
app.ports.outboundPort.subscribe(handleData);
// cleanup
app.ports.outboundPort.unsubscribe(handleData);| JavaScript | Elm |
|---|---|
| Booleans | Bool |
| Numbers | Int, Float |
| Strings | Char, String |
| Arrays | List, Array, Tuples |
| Objects | Records |
| JSON | Json.Encode.Value |
| null | Maybe Nothing |