cat/functor

Types

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

pub type ConstF(c)

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)

Phantom type for List Functor.

pub type ListF

Phantom type for Option Functor.

pub type OptionF

Phantom type for Reader Functor.

pub type ReaderF(r)

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 functor_compose(
  g: Functor(a, b, c, d, e),
  f: Functor(f, d, e, g, h),
) -> fn(fn(b) -> c) -> fn(g) -> h

Functor composition.
Is simply the composition of their fmaps.

Examples

Some([1, 2, 3])
|> functor_compose(list_functor(), option_functor())
( fn(x) { int.to_string(x + 1) } )
// -> Some(["2", "3", "4"])
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 reader_functor() -> Functor(
  ReaderF(a),
  b,
  c,
  fn(a) -> b,
  fn(a) -> c,
)

Reader Functor Instace.

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