Fantasy Land

Have you said "algebra"?

Specification for interoperability of common algebraic structures in JavaScript

(aka "Algebraic JavaScript Specification")

An algebra is a set of values, a set of operators that it is closed under and some laws it must obey.

Each Fantasy Land algebra is a separate specification. An algebra may have dependencies on other algebras which must be implemented.

Example: Ord

### Ord

A value that implements the Ord specification must
also implement the Setoid specification.

1. Totality:
  a['fantasy-land/lte'](b) or b['fantasy-land/lte'](a)

2. Antisymmetry:
  If a['fantasy-land/lte'](b) and b['fantasy-land/lte'](a)
  then a['fantasy-land/equals'](b)

3. Transitivity:
  If a['fantasy-land/lte'](b) and b['fantasy-land/lte'](c)
  then a['fantasy-land/lte'](c)

fantasy-land/lte :: Ord a => a ~> a -> Boolean

A value which has an Ord must provide a fantasy-land/lte method.
The fantasy-land/lte method takes one argument:

   a['fantasy-land/lte'](b)

1. b must be a value of the same Ord.

    1. If b is not the same Ord, behaviour of fantasy-land/lte is
       unspecified (returning false is recommended).

2. fantasy-land/lte must return a boolean (true or false).
### Setoid

1. Reflexivity:
  a['fantasy-land/equals'](a) === true

2. Symmetry:
  a['fantasy-land/equals'](b) === b['fantasy-land/equals'](a)

3. Transitivity:
  If a['fantasy-land/equals'](b) and b['fantasy-land/equals'](c)
  then a['fantasy-land/equals'](c)

fantasy-land/equals :: Setoid a => a ~> a -> Boolean

A value which has a Setoid must provide a 'fantasy-land/equals' method.
The 'fantasy-land/equals' method takes one argument:

  a['fantasy-land/equals'](b)

1. b must be a value of the same Setoid.

    1. If `b` is not the same Setoid, behaviour of `fantasy-land/equals`
       is unspecified (returning false is recommended).

2. fantasy-land/equals must return a boolean (true or false).

Sanctuary

Refuge from unsafe JavaScript

words[0].toUpperCase()
TypeError: Cannot read property 'toUpperCase' of undefined
S.map (S.toUpper) (S.head (words))

Unsafe?

|> R.tail ([])                      |> S.tail ([])
[]                                  Nothing

|> R.tail (['foo'])                 |> S.tail (['foo'])
[]                                  Just ([])

|> R.replace (/^x/) ('') ('abc')    |> S.stripPrefix ('x') ('abc')
'abc'                               Nothing

|> R.replace (/^x/) ('') ('xabc')   |> S.stripPrefix ('x') ('xabc')
'abc'                               Just ('abc')

So it's like Ramda?

lt :: Ord a => a -⁠> a -⁠> Boolean

Returns true iff the second argument is
less than the first according to Z.lt.

> S.filter (S.lt (3)) ([1, 2, 3, 4, 5])
[1, 2]



lte :: Ord a => a -⁠> a -⁠> Boolean

Returns true iff the second argument is
less than or equal to the first according to Z.lte.

> S.filter (S.lte (3)) ([1, 2, 3, 4, 5])
[1, 2, 3]

Our example

Sanctuary Type Classes

 Setoid   Semigroupoid  Semigroup   Foldable        Functor      Contravariant  Filterable
(equals)    (compose)    (concat)   (reduce)         (map)        (contramap)    (filter)
    |           |           |           \         / | | | | \
    |           |           |            \       /  | | | |  \
    |           |           |             \     /   | | | |   \
    |           |           |              \   /    | | | |    \
    |           |           |               \ /     | | | |     \
   Ord      Category     Monoid         Traversable | | | |      \
  (lte)       (id)       (empty)        (traverse)  / | | \       \
                            |                      /  | |  \       \
                            |                     /   / \   \       \
                            |             Profunctor /   \ Bifunctor \
                            |              (promap) /     \ (bimap)   \
                            |                      /       \           \
                          Group                   /         \           \
                         (invert)               Alt        Apply      Extend
                                               (alt)        (ap)     (extend)
                                                /           / \           \
                                               /           /   \           \
                                              /           /     \           \
                                             /           /       \           \
                                            /           /         \           \
                                          Plus    Applicative    Chain      Comonad
                                         (zero)       (of)      (chain)    (extract)
                                            \         / \         / \
                                             \       /   \       /   \
                                              \     /     \     /     \
                                               \   /       \   /       \
                                                \ /         \ /         \
                                            Alternative    Monad     ChainRec
                                                                    (chainRec)
lte :: (a, b) -⁠> Boolean
Returns true if its arguments are of the same type and the first is less than or equal to the second according to the type's fantasy-land/lte method; false otherwise.

fantasy-land/lte implementations are provided for the following built-in types: Null, Undefined, Boolean, Number, Date, String, Array, Arguments, and Object.

> lte (0, 0)
true

> lte (0, 1)
true

> lte (1, 0)
false

Our example

Read more

Fantasy Land

By Radosław Miernik

Fantasy Land

Vazco TechMeeting 2019-03-26

  • 1,159