cat/functor

Functor type {minimal implementation - fmap}.
Default implementation for: replace (<$ operator).
Functor composition and various functor instances: Option, List, Reader, Const, Tuple, Triple, Pair, Either.

Types

Phantom type for Const Functor.
We bind the first parameter of Const.

pub type ConstF(c)

Phantom type for Either Functor.

pub type EitherF(a)

Phantom type for Function Functor.

pub type FunctionF(r)

Functor type in gleam.

// Haskell type class
class Functor f where
    fmap :: (a -> b) -> f a -> f b

Functor laws

  • Preservation of identity: fmap id = id
  • Preservation of composition: fmap (g ∘ h) = (fmap g) ∘ (fmap h)

Since gleam does not have Higher Kinded Types, we cannot pass the type constructor to the Functor type.
We would like pass Option as f and then use f(a) as a type in the fmap definition.

Compromise

The user will follow this convention:

  • f: the first parameter of the Functor type is a phantom type used to differentiate between Functor instances
  • a, b: the second and third parameters are generic types
  • fa, fb: the fourth and fifth parameters are the constructed types f(a) and f(b) respectively

Examples

// The type that will be an instance of Functor:
type Identity(a) {
  Identity(a)
}
// The phantom type that will be the first parameter:
type IdentityF
// Instance of Identity for Functor (defined as a function to keep it generic over a and b)
let id_functor = fn() -> Functor(IdentityF, a, b, Identity(a), Identity(b)){
    Functor(fmap: fn(f) {
        fn(idx) {
            let Identity(x) = idx
            Identity(f(x))
        }
    })
}
// Use: the function id_functor needs to be called twice
// Each time it binds a and b (first to Int and Bool, second to Float and String)
let f = fn(x: Int) -> Bool { x % 2 == 0 }
identity_functor().fmap(f)(Identity(5))
// -> Identity(False)
let g = fn(x: Float) -> String { float.to_string(x) }
identity_functor().fmap(g)(Identity(6.0))
// -> Identity("6.0")
pub type Functor(f, a, b, fa, fb) {
  Functor(fmap: fn(fn(a) -> b) -> fn(fa) -> fb)
}

Constructors

  • Functor(fmap: fn(fn(a) -> b) -> fn(fa) -> fb)
pub type IdentityF

Phantom type for List Functor.

pub type ListF

Phantom type for Option Functor.

pub type OptionF

Phantom type for Pair Functor.

pub type PairF(a)

Phantom type for Reader Functor.

pub type ReaderF(r)

Phantom type for Triple Functor.

pub type TripleF(a, b)

Phantom type for Tuple Functor.

pub type TupleF(a)

Phantom type for Writer Functor.

pub type WriterF

Functions

pub fn const_functor() -> Functor(
  ConstF(a),
  b,
  c,
  Const(a, b),
  Const(a, c),
)

Const Functor Instance.

// Haskell instance
instance Functor (Const c) where
    fmap :: (a -> b) -> Const c a -> Const c b
    fmap _ (Const v) = Const v  
pub fn either_functor() -> Functor(
  EitherF(a),
  b,
  c,
  Either(a, b),
  Either(a, c),
)

Either Functor.

Examples

either_functor().fmap(bool.negate)(Left(27))
// -> Left(27)
either_functor().fmap(bool.negate)(Right(False))
// -> Right(True)
pub fn function_functor() -> Functor(
  FunctionF(a),
  b,
  c,
  fn(a) -> b,
  fn(a) -> c,
)

(->) Functor Instance.

// Haskell instance
instance Functor ((->) r) where
    fmap :: (a -> b) -> (r -> a) -> (r -> b)
    fmap f g = f ∘ g

Examples

let f = fn(x) { x % 2 == 0 }
let g = bool.to_string

function_functor().fmap(g)(f)(19)
// -> "False"
pub fn functor_compose(
  g: Functor(a, b, c, d, e),
  f: Functor(f, g, h, b, c),
) -> Functor(Pair(a, f), g, h, d, e)

Functor composition.
Is simply the composition of their fmaps.

Examples

Some([1, 2, 3])
|> functor_compose(option_functor(), list_functor()).fmap
( fn(x) { int.to_string(x + 1) } )
// -> Some(["2", "3", "4"])
pub fn identity_functor() -> Functor(
  IdentityF,
  a,
  b,
  Identity(a),
  Identity(b),
)

Identity Functor Instance.

// Haskell implementation
instance Functor Maybe where
    fmap :: (a -> b) -> Identity a -> Identity b
    fmap f (Identity x) = Identity(f x)

Examples

let f = fn(x: Int) -> Bool { x % 2 == 0 }
identity_functor().fmap(f)(Identity(5))
// -> Identity(False)
pub fn list_functor() -> Functor(ListF, a, b, List(a), List(b))

List Functor Instance.

// Haskell instance
instance Functor [] where
    fmap :: (a -> b) -> [a] -> [b]
    fmap _ [] = []
    fmap f (x:xs) = (f x):(fmap f xs)
pub fn option_functor() -> Functor(
  OptionF,
  a,
  b,
  Option(a),
  Option(b),
)

Option Functor Instance (generic over a and b).

// Haskell instance
instance Functor Maybe where
    fmap :: (a -> b) -> Maybe a -> Maybe b
    fmap _ Nothing = Nothing
    fmap f (Just x) = Just (f x)

Examples

let double = fn(x) { x * 2 }
option_functor().fmap(double)(None)
// -> None
Some(2)
|> option_functor().fmap(double)
// -> Some(4)
pub fn pair_functor() -> Functor(
  PairF(a),
  b,
  c,
  Pair(a, b),
  Pair(a, c),
)

Pair Functor.

Examples

pair_functor().fmap(bool.negate)(Pair(9, False))
// -> Pair(9, True)
pub fn reader_functor() -> Functor(
  ReaderF(a),
  b,
  c,
  Reader(a, b),
  Reader(a, c),
)

Reader Functor Instance.

// Haskell implementation
instance Functor (Reader r) where
  fmap :: (a -> b) -> Reader r a -> Reader r b
  fmap f g = f ∘ g

Examples

let ra = Reader(fn(x) { x % 2 == 0 })
let f = bool.to_string

reader_functor().fmap(f)(ra).apply(19)
// -> "False"
pub fn replace(functor: Functor(a, b, c, d, e)) -> fn(c, d) -> e

Haskell (<$) operator.

(<$) :: a -> f b -> f a
x <$ m = fmap (const x) m 

Examples

replace(option_functor())("a", Some(2))
// -> Some("a")
replace(option_functor())("a", None)
// -> None
pub fn triple_functor() -> Functor(
  TripleF(a, b),
  c,
  d,
  #(a, b, c),
  #(a, b, d),
)

Triple Functor.

Examples

triple_functor().fmap(bool.negate)(#("abc", 9, False))
// -> #("abc", 9, True)
pub fn tuple_functor() -> Functor(
  TupleF(a),
  b,
  c,
  #(a, b),
  #(a, c),
)

Tuple Functor.

Examples

tuple_functor().fmap(bool.negate)(#(9, False))
// -> #(9, True)
pub fn writer_functor() -> Functor(
  WriterF,
  a,
  b,
  Writer(a),
  Writer(b),
)

Writer Functor Instance.

// Haskell Instance
fmap :: (a -> b) -> Writer a -> Writer b
fmap f = id >=> (\x -> return (f x))

Examples

monad.Writer(16, "message")
|> writer_functor().fmap(fn(x) { x % 4 == 0 })
// -> monad.Writer(True, "message")
Search Document