There's a long thread in 2011 talking about monad,
but that discussion is not very clear and not what
I am going to talk about.
https://groups.google.com/d/msg/fricas-devel/UCFkQGgOOf0/oj9-FygocVgJ
The motivation get me into this topic is simple:
In OpenAxiom, I see there's a Maybe domain instead
of Union(T, "failed"). I want to have Maybe in FriCAS.
However, unlike Haskell, Maybe in OpenAxiom is not
a Monad.
So I did some research about how to implement Monad
in FriCAS:
## Functor
First, a simpler concept, Functor. OpenAxiom has this
Category defined, basicly, exports 'map(S->S, %)->%'.
I think FriCAS should also use this Categoty, ")dis op map" gives
81 exposed and 15 unexposed signature, that's too messy.
This Functor category is easy to understand, but it can't
handle more than 2 types:
map : (A->B, Functor A) : Functor B
It is impossible to export this signature in a category, and I use
a "hacky" method to implement it, see FunctorPackage bellow.
## Maybe
Maybe is an abstraction over Union(T, "failed"), but it also has
some property: Maybe is a Functor and a Monad.
See the implementation of "map" in Maybe and FunctorPackage.
## Monad
Functor is a category exports map : (S -> S, %) -> %,
Monad is a category exports bind : (S -> %, %) -> %,
or its infix form (% >>= (S -> %)) : %
For more than 2 types,
bind : (A -> Monad B, Monad A) -> Monad B
>>= : (Monad A, A -> Monad B) -> Monad B
It seems that FriCAS doesn't support infix operator with
3 letters, I use "_>_>" in the code bellow.
## Usage
This is just a simple example:
myinv(x:FRAC INT):Maybe FRAC INT == if x = 0 then nothing()$Maybe(FRAC
INT) else just(1/x)
(3) -> myinv 4
1
(3) ─
4
Type: Maybe(Fraction(Integer))
(4) -> myinv 0
(4) ()
Type: Maybe(Fraction(Integer))
(5) -> myinv 4 >> myinv
(5) 4
Type: Maybe(Fraction(Integer))
(6) -> myinv 0 >> myinv
(6) ()
Type: Maybe(Fraction(Integer))
Compared with:
(7) -> inv 4
1
(7) ─
4
Type: Fraction(Integer)
(8) -> inv inv 4
(8) 4
Type: Fraction(Integer)
(9) -> inv inv 0
>> Error detected within library code:
not invertible
##
This is just a "proof of concept" version, you can see the
Haskell version of Maybe from here:
https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Maybe.html
So, do you support implement such Functor/Monad/Maybe
in FriCAS?
======
)abbrev category FUNCTOR Functor
Functor(S : Type) : Category == Type with
map: (S -> S, %) -> %
)abbrev category MONAD Monad
Monad(S : Type) : Category == Type with
_>_> : (%, S -> %) -> %
)abbrev domain MAYBE Maybe
Maybe(T : Type) : Public == Private where
Public == Join(RetractableTo T, Functor T, Monad T) with
just : T -> %
++ \spad{just x} injects the value `x' into %.
fromJust : % -> T
nothing? : % -> Boolean
nothing : () -> %
++ \spad{nothing} represents failure or absence of value.
if T has CoercibleTo OutputForm then CoercibleTo OutputForm
Private == add
Rep := Union(T, "failed")
just x == x
nothing() == "failed"
nothing? x == x case "failed"
fromJust x ==
nothing? x => error "nothing in fromJust"
x@T
map(f, x) ==
nothing? x => nothing()
just f fromJust x
_>_>(x, f) ==
nothing? x => nothing()
f fromJust x
if T has CoercibleTo OutputForm then
coerce(x: %): OutputForm ==
nothing? x => paren(empty()$OutputForm)$OutputForm
(x@T)::OutputForm
)abbrev package FUNCTOR2 FunctorPackage
FunctorPackage(A : Type, B : Type, FA : Functor A, FB : Functor B) :
Exports == Implementation where
Exports == with
map : (A -> B, FA) -> FB
Implementation == add
if FA is Maybe A and FB is Maybe B then
map(f, fa) ==
if nothing?(fa)$Maybe(A) then nothing()$Maybe(B)
just f fromJust fa
)abbrev package MONADPKG MonadPackage
MonadPackage(A : Type, B : Type, MA : Monad A, MB : Monad B) :
Exports == Implementation where
Exports == with
bind : (A -> MB, MA) -> MB
_>_> : (MA, A -> MB) -> MB
Implementation == add
if MA is Maybe A and MB is Maybe B then
bind(f, fa) ==
if nothing?(fa)$Maybe(A) then nothing()$Maybe(B)
f fromJust fa
_>_>(fa, f) ==
bind(f, fa)