;-------------------------------------------------------------------------------
; setcat.cam = a simplistic model of set theory (based one category Set)
; in CAMILA
;-------------------------------------------------------------------------------
; Creation date : 1999.03.31
; Last update : 1999.04.29
; Last update : 1999.10.22
; (c) UM - M.F.P. II - 1998/99
;-------------------------------------------------------------------------------
;--- (a) Basics ----------------------------------------------------------------
; una is a generic function which converts a binary function into a unary
; function on pairs.
una(f)=lambda(p).f(p1(p),p2(p));
;;; f() -> f'(a,b)
; bin does the opposite of 'una'
bin(f)=lambda(a,b).f();
; flip permutes the order of arguments of a binary function
flip(f)=lambda(b,a).f(a,b);
; perm outputs a permutation of finite set s
perm(s)= < a | a <- s >;
;;; permut
permut(s)= if(s is-{} -> {<>},
s is- -> { let(e = hd(x)) in
{ | x <- permut(r) }| x <- s },
s is- -> { | x <- permut(r) },
s is-{e:r} -> { | x <- permut(r) }) ;
; get : B --> A --> (A -> B) --> B
; get totalizes a partial function (f) with a default value (u)
get(u)=lambda(a).lambda(f).if a in dom(f) then f[a] else u;
;;; ou entao
jjget(u)=lambda(a).lambda(f).ap(f,a,u);
eqk(k)= lambda(x).x==k;
inseq(n) = perm(inseg(n));
uplus <- una(plus);
PLUS(s) = plus-orio([],s);
MAX(s) = max-orio(0,s);
selUp(s,f)=lambda(x). x + ((*->f)(x/s));
pred(n)=n.-1;
succ(n)=n.+1;
;--- (b) CCC -------------------------------------------------------------------
; id : A --> A
id(x)=x;
; comp : (C <-- B) x (B <-- A) --> (C <-- A)
comp(f,g)= lambda(x).f(g(x));
;;; NOTA = _comp
; const : C --> (A --> C)
const(c)= lambda(x).c;
; excl : A --> 1
excl <- const(NIL);
; curry : (A x B --> C) --> A --> (B -->C)
curry(f) = lambda(a).lambda(b).f('a,b);
; i1 : (A + B) <-- A
i1(a) = <1,a>;
; i2 : (A + B) <-- B
i2(b) = <2,b>;
; grd : (A --> 2) --> A --> (A + A)
grd(p) = lambda(x). if p(x) then i1(x) else i2(x);
; is1 : ( A + B ) --> 2
is1(x) = p1(x)==1;
; is2 : ( A + B ) --> 2
is2(x) = p1(x)==2;
; split : ( A --> B x C ) <-- ( A --> B ) x ( A --> C )
split(f,g)= lambda(x).<'f(x),'g(x)>;
; either : (A --> C) x (B --> C) --> ((A + B) --> C)
either(f,g)=lambda(x).let (t=p1(x),y=p2(x)) in if t==1 then 'f(y) else 'g(y);
; prod : (A --> B) x (C --> D) --> ((A x C) --> (B x D))
prod(f,g) = split(comp(f,p1),comp(g,p2));
; diag : (A --> B) --> ((A x A) --> (B x B))
; diag is the diagonal functor construct
diag(f) = prod(f,f);
; sum : (A --> B) x (C --> D) --> ((A + C) --> (B + D))
sum(f,g) = either(comp(i1,f),comp(i2,g));
; swap : (A x B) --> (B x A)
swap <- split(p2,p1);
; assocr : (A x B) x C --> A x (B x C)
assocr <- split(comp(p1,p1),prod(p2,id));
; assocl : A x (B x C) --> (A x B) x C
assocl <- split(prod(id,p1),comp(p2,p2));
; pwnil : A --> (A x 1) /* pwnil = pair with NIL */
pwnil <- split(id,excl);
; coswap : (A + B) --> (B + A)
coswap <- either(i2,i1);
; coassocr : ((A + B) + C) --> (A + (B + C))
coassocr <- either(sum(id,i1),comp(i2,i2));
; undistr : A x ( B + C ) <-- ( ( A x B ) + ( A x C ) )
undistr <- either(prod(id,i1),prod(id,i2));
; split0 : (A --> 1) <-- 1
split0 <- lambda(x). const(NIL);
; uneither0 : 1 <-- (0 --> A)
uneither0 <- lambda(x). NIL;
; untab : ( A -> B ) --> (A -> (B + 1))
untab(sigma)=comp(sum(curry(ap)(sigma),excl),grd(lambda(a).a in dom(sigma)));
; cf : ( A --> 2 ) <-- A-set /* cf = characteristic function */
cf(s) = lambda(a).a in s;
; pair2exp : ( 2 --> A ) <-- A x A
; an isomorphism
pair2exp(p) = lambda(b). if b then p2(p) else p1(p);
; nestr : A × B × C --> A × (B × C)
nestr <- split(p1,split(p2,p3));
; nestl : A × B × C --> (A × B) × C
nestl <- split(split(p1,p2),p3);
; flatr : A × (B × C) --> A × B × C
flatr(t)=;
; flatl : (A × B) × C --> A × B × C
flatl(t)=;
;--- (c) Partial maps ----------------------------------------------------------
; set2fm : ( A -> 1 ) <-- A-set
; dom is the inverse of set2fm
set2fm(s) = [ x -> NIL | x <- s ];
; peither : ( ( A + B ) -> C ) <-- ( A -> C ) x ( B -> C )
; This is the "partial version" of either
peither(f1,f2) = (i1->*)(f1) + (i2->*)(f2);
; unpeither : ( ( A + B ) -> C ) --> ( A -> C ) x ( B -> C )
; The inverse of (unary) unpeither
unpeither(f) = let (a=[ p2(x) -> f[x] | x <- dom(f): p1(x) == 1 ],
b=[ p2(x) -> f[x] | x <- dom(f): p1(x) == 2 ])
in < a , b >;
; join : ( A -> B x C ) <-- ( A -> B ) x ( A -> C )
; This is the "partial version" of split
join(f1,f2) = [ a -> < f1[a],f2[a]> | a <- dom(f1) * dom(f2) ];
join_ <- una(join);
; unjoin : ( A -> B x C ) --> ( A -> B ) x ( A -> C )
; The right-inverse of join_, ie join_ . unjoin = id.
unjoin <- split(*->p1,*->p2);
; pcurry : (A x B -> C) --> A -> (B->C)
; pcurry is the "partial version" of curry.
; It is not epic and therefore not iso
pcurry(f) =
let (x=dom(f), y=p1-set(x))
in [ a -> [ p2(p) -> f[p] | p <- x : p1(p)==a ] | a <- y ];
; unpcurry : (A x B -> C) <-- A -> ( B -> C )
; unpcurry is the "partial version" of uncurry.
; It is not monic and therefore not iso
unpcurry(f) =
PLUS({ let (g=f[a]) in [ -> g[b] | b <- dom(g) ] | a <- dom(f) });
; collect : (A x B)-set --> A -> B-set
; collect can be calculated from pcurry and set2fm
collect(r) = [ a -> { p2(q) | q <- r: a==p1(q) } | a <- { p1(p) | p <- r } ];
; discollect : (A x B)-set <-- A -> B-set
; discollect can be calculated from unpcurry and set2fm
discollect(f) = UNION({ { | b <- f[a] } | a <- dom(f) });
; njoin : ((A -> D) x (A x B -> C)) --> (A -> D x (B->C))
; njoin (read: 'nested join') is epic but not mono
njoin <- comp(join_,split(p1,comp(uplus,prod((*->const([])),pcurry))));
; unnjoin : ((A -> D) x (A x B -> C)) <-- (A -> D x (B->C))
; njoin . unnjoin = id, ie. unnjoin is njoin's right-inverse.
unnjoin <- comp(prod(id,unpcurry),unjoin);
; cojoin : ( A -> (B + C) ) <-- ( A -> B ) x ( A -> C )
cojoin(f,g) = let (h=f\dom(g), i=g\dom(f)) in (*->i1)(h) + (*->i2)(i);
; uncojoin : ( A -> (B + C) ) --> ( A -> B ) x ( A -> C )
uncojoin(f) = let (x={ a | a <- dom(f): is1(f[a]) },
y={ a | a <- dom(f): is2(f[a]) })
in <(*->p2)(f/x),(*->p2)(f/y)>;
; ffinv : (A -> B) --> (B -> A-set)
; ffinv(f) "reverses" f.
ffinv(f) = [ b -> { a | a<- dom(f): f[a]==b } | b <- ran(f) ];
; unffinv : (A -> B) <-- (B -> A-set)
; unffinv is ffinv's right inverse, that is ffinv . unffinv = id
unffinv(f)= let (x={ [ a -> b | a <- f[b] ] | b <- dom(f) },
y={ f \ UNION(dom-set(x-{f})) | f <- x })
in PLUS([],y);
; mkf : (A -> B) <-- (A x B)-set
; This is partial function !
mkf <- comp((*->the),collect); /* ie [ p1(t) -> p2(t) | t <- r ] */
; mkr : (A -> B) --> (A x B)-set
mkr(f) = { | a <- dom(f) };
;--- (d) Sequences -------------------------------------------------------------
; fm2seq : A-seq <-- (NAT -> A)
; Turns a numeric index of A-values into the implicit sequence
fm2seq(f) =
if f==[] then <> else let (m=MAX(dom(f))) in fm2seq(f\{m}) ^ < f[m] >;
; seq2fm : A-seq --> (NAT -> A)
; A sequence is represented by a numerical index keeping track of the original
; order. Right-inverse of fm2seq.
seq2fm(l) = [ x -> l[x] | x <- inseg(length(l)) ];
; zip : (B x C)-seq <-- B-seq x C-seq
; This is the "seq version" of join
zip(l,m) =
let (n=min(length(l),length(m))) in < < l[i],m[i] > | i <- inseq(n) >;
; unzip : (B x C)-seq --> B-seq x C-seq
; The right-inverse of una(zip), ie una(zip) . unzip = id.
unzip <- split(p1-seq,p2-seq);
;--- (e) X = 1 + A x X structure hylo ------------------------------------------
inF <- either(const(<>),una(cons));
outF <- comp(sum(const(nil),split(hd,tl)),grd(eqk(<>)));
recF(f)=sum(id,prod(id,f));
cata(g) = lambda(x).(comp(g,comp(recF(cata(g)),outF)))(x);
ana(g) = lambda(x).(comp(inF,comp(recF(ana(g)),g)))(x);
hylo(h,g) = comp(cata(h),ana(g));
;--- (e.1) application to set-folding ------------------------------------------
; nsetget : A-set --> A x A-set
; nsetget is undefined for the empty set
nsetget(s) = let (a=choice(s)) in ;
; gets : A-set --> 1 + A x A-set
; gets is the A-set standard coalgebra
gets <- comp(sum(const(NIL),nsetget),grd(eqk({})));
; tot2 : (B x B -> B) x B --> (A x B)-set --> B
; tot2 totalizes a binary relation on the second projection according to
; monoid structure f: B x B -> B and u: B
tot2(f,u)= hylo(either(const(u),comp(una(f),prod(p2,id))),gets);
;--- (e.2) application to Nat-folding ------------------------------------------
getN <- comp(sum(const(nil),split(id,pred)),grd(eqk(0)));
fac <- hylo(either(const(1),una(mul)),getN);