The Gleam Tour is helpful.
@external
@external
can be used to import any erlang function. You must specify their type signatures, but notice in the example below that you can make that signature fully generic.
(You do need to specify the correct number of args. If a function has two different forms, like io:format/1
and io:format/2
, that's two different functions--you can't import them both at once.)
Several useful functions, including format
, can be found in the io
module to help you on printing in almost every hole.
io:format/2
is a printf-style function that takes a format string (check out the documentation for syntax) and a list of args to interpolate. Some format specifiers are broken due to mismatched data types between Gleam and Erlang, but ~p
is useful.
@external(erlang,"io","format")fn f(a:a,b:b)->z
format("~p bottles of beer",[99])
Erlang's documentation can be quite daunting. The paginated search can help. Some functions are available that aren't technically part of Erlang's "stdlib".
import
golfs
The order of top-level statements doesn't matter. Hence, if a top-level statement ends in }
, it shouldn't be the last one (unless all do), otherwise you waste a byte:
import gleam/io pub fn main(){}
pub fn main(){}import gleam/io
If you're using a module enough times, it can save to use as
:
int.a int.b int.c import gleam/int
i.a i.b i.c import gleam/int as i
If you are using one or more functions from a module enough times, use an unqualified import (the module itself is still imported):
l.map l.map import gleam/list as l
map map import gleam/list.{map}
l.map l.map l.max l.max import gleam/list as l
map map max max import gleam/list.{map,max}
as
can also be used within the {}
:
drop drop import gleam/list.{drop,map}
d d import gleam/list.{drop as d,map}
You can both use an unqualified import and alias the module name (the alias takes 4 bytes instead of 5 in this case):
l.drop l.max map map import gleam/list.{map}as l
Argv trick
You can use use
to save 1b looping through argv
list.map(argv.load().arguments,fn(x){...})
use x<-list.map(argv.load().arguments)...
Looping
range
+map
Sometimes can be too long
list.map(list.range(1,100),fn(x){...})
fold
This method can be better than map
under certain circumstances, be still needs the list
import
list.fold(list.range(1,100),start,fn(acc,x){...;new_x})
fn
A recursive function would work well in many scenarios because you can just avoid the list
import altogether, this is usually the best way to loop
pub fn main(){f(100,100)}
fn f(a,b){io.println(...)cond&&f(a*2,b/2)}
You can also use ||
instead of &&
if !cond
ends up shorter than cond
.
case
Generally it is better to avoid case
, but if you have to, and you know the possible values of your condition:
case a%20!=2{True->a _->0}
case a%20{2->0 _->a}
Printing
Newlines within string literals are allowed, hence it might be possible to save a byte by using print
instead of println
and writing the newline out manually.
Sometimes you have to print a value if a condition cond
is satisfied, and, in such a case, you might be inclined to use case
; however, remember that print
and println
return Nil
, and Nil==Nil
, hence you can do one of these:
cond&&Nil!=io.println(str)
!cond||Nil==io.println(str)
Nil
should be on the left side of the ==
, to save a space. The first version is always False
, and the second one is always True
(also consider if !cond
is shorter than cond
). If you want the expression's value to depend on cond
, change between ==
and !=
.
Unwrapping Result
s
Result types can be useful for production code, but they're near useless for code golf, since they almost always end up as successes. gleam_stdlib
provides unwrap
in gleam/result
, which returns the content of the Result
if it's Ok(...)
, and a default value if it's Error(...)
. For instance, unwrap(int.parse(str),0)
parses str
to an Int
, and returns 0
if str
doesn't have a valid integer.
However, to use it, you unfortunately have to include import gleam/result
in your code. Luckily, there is a shorter alternative, to just do the job manually, if you don't somehow need another function from gleam/result
(you might have to change the 0
to a value of the correct type):
result.unwrap(r,0)import gleam/result
case r{Ok(x)->x _->0}
If you'd have to use unwrap
multiple times, making a new function is still cheaper:
u(q,0)u(r,0)import gleam/result.{unwrap as u}
u(q)u(r)fn u(x){case x{Ok(x)->x _->0}}
If you have to handle different types, then you'll have to provide a default value, but literally reinventing unwrap
still saves:
u(q,0)u(r,"")import gleam/result.{unwrap as u}
u(q,0)u(r,"")fn u(x,y){case x{Ok(x)->x _->y}}
ASCII value
To get the ASCII value of a character
let assert<<a>>=<<"h">>
Misc tips
case a{b->0 _->1}
-> case a{b->0a->1}
string.to_graphemes(s)
-> string.split(s,"")
list.each
-> list.map
string.drop_start
-> string.drop_left
string.pad_start
-> string.pad_left
string.trim_start
-> string.trim_left