1. Introduction

Som is functional programming made simple. It offers everything the casual functional programmer would want in a straightforward and consise manner. Because of this, it is great for both those who are newcomers to functional programming and those who feel like the big functional languages like Haskell are a bit too complex or hard-to-read.

Naturally, the official Som compiler, somc, is written in OCaml and uses LLVM as backend to generate high-performance executables. This makes Som interoperable with most non-functional languages such as C and C++.

Som also comes with a standard library that's not bloated, yet provides everything necessary for most casual projects. And thanks to Som's interoperability with low-level languages such as C, any other low-level functionalities or existing libraries in other languages can easily be added.

Not unlike most reference manuals this one is not (yet) complete and might leave some questions unanswered. Please feel free to open an issue if you have any questions. Do however mind that Som, including its documentation, is still in development. Some example files can be found in the test/ directory Som's github repository.

"form follows function"

2. Hello World

The traditional "Hello World!" program implemented in Som looks as follows:

from std::io use puts

let main = puts "Hello, World!"

Let's break this down line by line.

The code starts with an import statement. Since we want to output, or "print" a string, we'll need to import the function that allows us to do that. In this case, that's the function puts from the io module of the standard library.

Next is the value binding of main. Every Som program needs to define a value called main, which is where that program's execution starts. In this case, all that main does is use the imported puts function to print a string.

And that's it! Since Som is designed to be easy to use, there's practically no boiler-plate needed; As long as there's an entrypoint like main the program will run!

Now let's test the program by compiling and executing it. If you haven't installed the compiler yet, follow the installation instructions first. After installing the compiler, save the program as hello_world.som and then invoke somc. You can then run the resulting executable:

$ # Linux or MacOS
$ somc hello_world.som
$ ./hello_world
Hello World!
$
> # Windows
> somc.exe hello_world.som
> ./hello_world.exe
Hello World!
>

5. The Standard Library

Som's standard library provides modules with values and types core to Som, both implemented natively or in C. Some of these modules provide functionality for accessing services "outside" of Som, such as I/O, while other modules implement trivial types such as List and Option.

Currently, Som's standard contains the following modules:

  • io for file I/O
  • list for the list type and related functions
  • ops for aliasing builtin operators
  • prelude for including basic features
  • ptr for the pointer type and related functions
  • str for the string type and related functions
  • types for aliasing common primitive types

The standard library's runtime implementation is mostly in C and is distributed in the dynamic library libsom.so on Linux and MacOS and in som.dll on Windows. When using the standard library the final executable has to be linked to this library, which is normally done automatically by the compiler. Any library or program extending- or using Som's standard library outside of Som has to link to the dynamic library manually.

5.1. The IO Module

The io module provides I/O functionality, such as opening files and printing to the terminal.

  Standard module containing types and functions for (file) input/output.

This module's most trivial functionality, such as printing to the terminal, is included in the prelude.

Types


IOMode

type IOMode of
  read,
  write,
  append,
  read_write

The different modes for opening a file.

File

type File of
  path: Str,
  descr: Int,
  mode: IOMode

A handle to a file.

Values


stdin

ext stdin : File

A read-only file handle to the standard input, "stdin".

stdout

ext stdout : File

An append-only file handle to the standard output, "stdout".

stderr

ext stderr : File

An append-only file handle to the standard error output, "stderr".

openf

ext openf path mode : Str -> IOMode -> !File

Opens the file with the given path and IOMode.

closef

ext closef file : File -> !Nll

Closes the given file.

putsf

ext putsf file str : File -> Str -> !Nll

Writes string str to the given File, if it has been opened with mode write, read_write or append.

puts

let puts str : Str -> !Nll

Prints the given string to stdout.

Imports


Publicly imported symbols:

from std::str use Str

View the source code here.

5.2. The Prelude Module

The prelude module provides basic features and is (when not disabled) automatically included in every Som file.

  Standard module implicitly imported by default into all Som modules unless
  explicitly disabled using the `no_prelude` or `no_stdlib` directive.

Manually having to import even the most trivial and commonly used symbols in every file would be overly verbose and tedious. Hence, this prelude is automatically imported in each Som file. It's kept as simple and light-weight as possible.

Values


return

let return v : 'a -> !'a

Wraps any value v in an effect.

exit

!!no_return
ext exit status : Int -> Nll

Terminates the calling process immediately with the given status.

assert

let assert cond msg : Bln -> Str -> Nll

Asserts that cond is true, and if not, prints msg to stderr before exiting with code 1.

Imports


Publicly imported symbols:

from std::types use *
from std::ops use *
from std::str use Str

Private dependencies:

use std::types
use std::list
use std::ops
use std::str
from std::io use putsf, stderr

View the source code here.

7. The Complete Syntax

Here is the complete syntax of Som in a simplified BNF. Do note that it might be incomplete due to the continuing development of the Som language. The irony of this has been duly noted.

program            = toplevel*

toplevel           = import_statement
                   | module_definition
                   | value_definition
                   | type_definition
                   | extern_definition

import_statement   = "use" LONG_LIDENT
                   | "from" LONG_LIDENT "use" "*"
                   | "from" LONG_LIDENT "use" (LONG_IDENT ",")* LONG_IDENT

module_definition  = "mod" "{" toplevel* "}"

value_definition   = "let" LIDENT pattern* "=" expression

type_definition    = "type" PIDENT* UIDENT "is" type
                   | "type" PIDENT* UIDENT "of" complex_type
                   
extern_definition  = "ext" LIDENT ":" type
                   | "ext" LIDENT "as" LIDENT pattern* ":" type

complex_type       = "|"? variant ("|" variant)*
                   | "{" (field ("," field)*)? "}"
                   
variant            = UIDENT (type (";" type)*)?
field              = LIDENT ":" type

type               = forall_type
forall_type        = (PIDENT+ ".")? function_type
function_type      = (function_type "->")? tuple_type
tuple_type         = constructed_type (";" constructed_type)*
constructed_type   = effect_type LONG_UIDENT?
effect_type        = "!"* atom_type
atom_type          = "(" type ")"
                   | PRIMITIVE_TYPE
                   | PIDENT
                   | LONG_UIDENT

pattern            = atom_pattern
atom_pattern       = LIDENT
                   | "_"

expression         = let_epxr
                   | sequence_expr
let_epxr           = "let" LIDENT pattern* "=" let_epxr "in" let_epxr
sequence_expr      = (sequence_expr ",")? lambda_expr
lambda_expr        = ("\\" pattern* "->") tuple_expr
tuple_expr         = contraint_expr (";" constraint_expr)*
constraint_expr    = BASIC_EXPR (":" type)?

The meaning of the tokens such as LIDENT are as follows:

tokenmeaning
IDENTAny identifier, such as foo, Bar or baz'
LIDENTA lowercase identifier, such as foo
UIDENTAn uppercase identifier, such as Bar
PIDENTA lowercase identifier starting with a ', such as 'var
LONG_*The qualified version of the identifier, such as foo::Bar
PRIMITIVE_TYPEA primitive type, such as $i.s.32 or $f.*
BASIC_EXPRA simple expression, such as 1 + 2 or "foo"

8.3. License

The following license applies to every component of the som compiler, its standard library and its tools. In other words, it applies to the entire contents of the github repository SjVer/Som-Lang.

MIT License

Copyright (c) 2022-2023 Sjoerd Vermeulen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

This license simply means that anyone is free to use Som for any purpose. The only requirement for copying or reusing any part of the aforementioned source code or assets is that credit is given by including the above license.

std/ptr.som

Module documentation here.

---
  Module std::ptr
  Standard module containing the pointer type as well as functions for
  performing operations on- and with pointers.

  This file is part of the Som standard library.

  Copyright (c) 2023 Sjoerd Vermeulen

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
---

-- !!.stdlib
-- !!.warn_redef "redefinition may break stdlib"

type 'a Ptr is $i.u.s

-- !!unsafe
ext _som_std_ptr_deref as deref ptr : 'a Ptr -> 'a

-- !!unsafe
ext _som_std_ptr_set as set ptr val : 'a Ptr -> 'a -> !Nil

let is_null ptr : 'a Ptr -> Bln = ptr = 0

-- !!unsafe
ext _som_std_ptr_malloc as malloc size : Sze -> !'a Ptr

let malloc_ptr () : !'a Ptr = malloc (!!size_of 'a)

ext _som_std_ptr_free as free ptr : 'a Ptr -> !Nil

std/ops.som

Module documentation here.

---
  Module std::ops
  Standard module containing functions for basic operators.

  This file is part of the Som standard library.

  Copyright (c) 2023 Sjoerd Vermeulen

  Permission is hereby granted, free of charge, to any person obtaining x copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
---

-- !!.stdlib
-- !!.warn_redef "redefinition may break stdlib"

--- arithmetic ops ---

let (+) : Int -> Int -> Int = #add_int
let (-) : Int -> Int -> Int = #sub_int
let (*) : Int -> Int -> Int = #mul_int
let (/) : Int -> Int -> Int = #div_int
let (%) : Int -> Int -> Int = #rem_int
let (~+) : Int -> Int = #abs_int
let (~-) : Int -> Int = #neg_int

--- logical ops ---

let (&&) : Bln -> Bln -> Bln = #and
let (||) : Bln -> Bln -> Bln = #or
let (~!) : Bln -> Bln = #not

--- comparison ops ---

let (=) : Int -> Int -> Bln = #eq
let (/=) : Int -> Int -> Bln = #neq
let (==) : 'a . 'a -> 'a -> 'a = #eq_value
let (/==) : 'a . 'a -> 'a -> 'a = #neq_value
let (<) : Int -> Int -> Bln = #lt_int
let (<=) : Int -> Int -> Bln = #lteq_int
let (>) : Int -> Int -> Bln = #gt_int
let (>=) : Int -> Int -> Bln = #gteq_int

std/list.som

Module documentation here.

---
  Module std::list
  Standard module containing the list types and functions for list operations.

  This file is part of the Som standard library.

  Copyright (c) 2023 Sjoerd Vermeulen

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
---

-- !!.stdlib
-- !!.warn_redef "redefinition may break stdlib"

type 'a List of Cons 'a ; 'a List | Nil

let concat l1 l2 : 'a List -> 'a List -> 'a List =
  match l1
    | Cons hd ; tl then Cons (hd ; concat tl l2)
    | Nil then l2

let append l x : 'a List -> 'a -> 'a List =
  concat l (Cons (x ; Nil))


let map f l: ('a -> 'b) -> 'a List -> 'b List =
  match l
    | Cons hd ; tl then Cons (f hd ; map f tl)
    | Nil then Nil

std/str.som

Module documentation here.

---
  Module std::str
  Standard module containing the basic Str type as well as functions for
  performing operations on- and with strings.

  This file is part of the Som standard library.

  Copyright (c) 2023 Sjoerd Vermeulen

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
---

-- !!.stdlib
-- !!.warn_redef "redefinition may break stdlib"

from std::ptr use Ptr

type Str is Chr Ptr

ext _som_std_str_length as length str           : Str -> Sze
ext _som_std_str_concat as concat str1 str2     : Str -> Str -> Str
ext _som_std_str_substr as substr str start len : Str -> Str -> Str
ext _som_std_str_split  as split  str delim     : Str -> Str -> Str
ext _som_std_str_lstrip as lstrip str delim     : Str -> Str -> Str
ext _som_std_str_rstrip as rstrip str delim     : Str -> Str -> Str

let strip str delim: Str -> Str -> Str = lstrip (rstrip str delim) delim

std/prelude.som

Module documentation here.

---
	Module std::prelude
	Standard module implicitly imported by default into all Som modules unless
	explicitly disabled using the `no_prelude` or `no_stdlib` directive.

	This file is part of the Som standard library.

	Copyright (c) 2023 Sjoerd Vermeulen

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.
---

-- !!.stdlib
-- !!.warn_redef "redefinition may break stdlib"

--- public imports ---

from std::ops use *
from std::str use Str
from std::list use List

--- private imports ---

from std::io use
	putsf as _putsf,
	stderr as _stderr

--- functions ---

-- wraps a value in an effect
let return v : 'a -> !'a = v

-- terminates the calling process immediately with the given status
!!no_return
ext _som_std_prelude_exit as exit status : Int -> Nil

let assert cond msg : Bln -> Str -> Nil =
	if cond then
		_putsf _stderr msg,
		exit 1
	else ()

std/io.som

Module documentation here.

---
  Module std::io
  Standard module containing types and functions for (file) input/output.

  This file is part of the Som standard library.

  Copyright (c) 2023 Sjoerd Vermeulen

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
---

-- !!.stdlib
-- !!.warn_redef "redefinition may break stdlib"

from std::str use Str

--- types ---

type IOMode of
  read,
  write,
  append,
  read_write

type File of
  path: Str,
  descr: Int,
  mode: IOMode

--- files ---

ext _som_std_io_stdin  as stdin  : File 
ext _som_std_io_stdout as stdout : File 
ext _som_std_io_stderr as stderr : File 

--- functions ---

-- opens the file with the given path and mode
ext _som_std_io_openf as openf path mode : _Str -> IOMode -> !File

-- closes the given file
ext _som_std_io_closef as closef file : File -> !Nil

-- writes the given string to the given file
ext _som_std_io_putsf as putsf file str : File -> _Str -> !Nil

-- prints the given string to stdout
let puts str : _Str -> !Nil = putsf stdout str, putsf stdout "\n"