The Gleam programming language, with cat package

Introduction

The Gleam programming language targets BEAM and JavaScript. Gleam is statically typed, which has proven to be hard to live without if you're used to it. Like Gloogle, which allows you to search by types (similar to Hoogle.

Gloogle query examples -- hint: try the Filters1 (e.g. Functions, Documented):

List(a) -> Int

or

(List(a), fn(a, a) -> a) -> a

The cat package

The cat package implements category theory concepts in gleam. Some experimenting with the latest cat.

The main branch from the cat repo is used via this under [dependencies] in gleam.toml:

1cat = { git = "https://github.com/VSebastian8/cat.git", ref = "main" }

The code for the examples I have been experimenting with can be viewed here: photonsphere/cat_examples.

Highlights:

 1import cat.{type Either, Left, Right}
 2import cat/applicative as app
 3import cat/bifunctor as bf
 4import cat/functor.{functor_compose}
 5import cat/instances/applicative as appi
 6import cat/instances/bifunctor as bfi
 7import cat/instances/functor as funi
 8import cat/instances/monad.{Reader, Writer, fish, reader_return, writer_return}
 9import cat/instances/monoid as moni
10import cat/monoid.{type Monoid, Monoid, mconcat}
11import gleam/int
12import gleam/option.{None, Some}
13import gleam/string
14
15pub fn main() {
16  // Monoid example from README (somewhat adapted).
17  let either_sum_monoid =
18    Monoid(
19      mempty: Left(0),
20      mappend: fn(e1: Either(Int, String), e2: Either(Int, String)) -> Either(
21        Int,
22        String,
23      ) {
24        case e1, e2 {
25          Right(s), _ -> Right(s)
26          _, Right(s) -> Right(s)
27          Left(a), Left(b) -> Left(a + b)
28        }
29      },
30    )
31
32  either_sum_monoid
33  |> mconcat([Left(2), Left(3), Left(4)])
34  |> echo
35  echo " ---> Left(9)"
36
37  either_sum_monoid
38  |> mconcat([Left(2), Right("error"), Left(4)])
39  |> echo
40  echo " ---> Right(\"error\")"
41  
42  // Functor example from README (somewhat adapted).
43  option.Some([1, 2, 3])
44  |> functor_compose(funi.option_functor(), funi.list_functor()).fmap(fn(x) {
45    x % 2 == 0
46  })
47  |> echo
48  echo " ---> Some([False, True, False])"
49
50  // Applicative example from README (somewhat adapted).
51  [Some(1), None, Some(3)]
52  |> {
53    [fn(x) { x * 2 }, fn(x) { x + 10 }]
54    |> funi.list_functor().fmap(funi.option_functor().fmap)
55    |> app.apply(appi.list_applicative())
56  }
57  |> echo
58  echo " ---> [Some(2), None, Some(6), Some(11), None, Some(13)"
59
60  // Bifunctor examples from README (somewhat adapted)
61  // Either bifunctor
62  let either_bf = bfi.either_bifunctor()
63  // Const () functor
64  let const_f = funi.const_functor()
65  // Identity functor
66  let id_f = funi.identity_functor()
67
68  // Constructing the maybe functor:
69  // Maybe b = Either (Const () a) (Identity b)
70  let maybe_functor = fn() -> bf.Bifunctor(
71    bf.BiCompF(bfi.EitherBF, funi.ConstF(Nil), funi.IdentityF),
72    a,
73    b,
74    c,
75    d,
76    cat.Either(cat.Const(Nil, a), cat.Identity(b)),
77    cat.Either(cat.Const(Nil, c), cat.Identity(d)),
78  ) {
79    bf.bifunctor_compose(either_bf, const_f, id_f)
80  }
81
82  cat.Left(cat.Const(Nil))
83  |> maybe_functor().bimap(fn(_) { panic }, int.to_string)
84  |> echo
85  echo " ---> Left(Const(Nil)"
86
87  cat.Right(cat.Identity(3))
88  |> maybe_functor().bimap(fn(_) { panic }, int.to_string)
89  |> echo
90  echo " ---> Right(Identity(\"3\")"
91}

  1. Apparently Filters are not available on the mobile Gloogle site ↩︎

Posts in this Series