The Gleam Tour is helpful.
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