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/Olist
for the list type and related functionsops
for aliasing builtin operatorsprelude
for including basic featuresptr
for the pointer type and related functionsstr
for the string type and related functionstypes
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:
token | meaning |
---|---|
IDENT | Any identifier, such as foo , Bar or baz' |
LIDENT | A lowercase identifier, such as foo |
UIDENT | An uppercase identifier, such as Bar |
PIDENT | A lowercase identifier starting with a ' , such as 'var |
LONG_* | The qualified version of the identifier, such as foo::Bar |
PRIMITIVE_TYPE | A primitive type, such as $i.s.32 or $f.* |
BASIC_EXPR | A 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"