module Encoded.Container import Encoded.Arith import Encoded.Bool import Encoded.Fin import Encoded.Pair import Encoded.Sum import Encoded.Vect import Term.Syntax %ambiguity_depth 6 %prefix_record_projections off -- Utilities ------------------------------------------------------------------- gtabulate : {sx : SnocList a} -> ({x : a} -> Elem x sx -> p (f x)) -> All p (map f sx) gtabulate {sx = [<]} g = [<] gtabulate {sx = sx :< x} g = gtabulate (g . There) :< g Here -- Adds a value to the start of a stream cons : {ty : Ty} -> Term (ty ~> (N ~> ty) ~> (N ~> ty)) ctx cons = Abs $ Abs $ Abs $ let x = Var (There $ There Here) in let xs = Var (There Here) in let n = Var Here in App rec [ Ty -> Ty semCase (Just tag, k) ty = tag * Vect k ty semCase (Nothing, k) ty = Vect k ty unitCase : Case -> Ty unitCase (Just tag, k) = tag unitCase (Nothing, k) = N forgetCase : {c : Case} -> {ty : Ty} -> Term (semCase c ty ~> unitCase c) ctx forgetCase {c = (Just tag, k)} = fst forgetCase {c = (Nothing, k)} = Arb dmapCase : {c : Case} -> {ty, ty' : Ty} -> Term ((Fin (snd c) ~> ty ~> ty') ~> semCase c ty ~> semCase c ty') ctx dmapCase {c = (Just tag, k)} = Abs' (\f => App (mapSnd . dmap) [ {ty : Ty} -> Term (semCase c ty ~> Vect (snd c) ty) ctx children {c = (Just tag, k)} = snd children {c = (Nothing, k)} = Id -- Containers ------------------------------------------------------------------ public export record Container where constructor Cases constructors : SnocList Case {auto 0 ok : NonEmpty constructors} %name Container c public export sem : Container -> Ty -> Ty sem c ty = Sum (map (flip semCase ty) c.constructors) @{mapNonEmpty c.ok} unitSem : Container -> Ty unitSem c = Sum (map unitCase c.constructors) @{mapNonEmpty c.ok} -- Fixed Point ---------------------------------------------------------------- export W : Container -> Ty W c = (N ~> N * unitSem c * N * N) -- ^ ^- data ^ ^- stride -- +- fuel +- base fuelAt : {c : Container} -> Term (W c ~> N ~> N) ctx fuelAt = Abs' (\c => fst . fst . fst . c) fuel : {c : Container} -> Term (W c ~> N) ctx fuel = Abs' (\c => App fuelAt [ Term (W c ~> N ~> unitSem c) ctx vals = Abs' (\c => snd . fst . fst . c) base : {c : Container} -> Term (W c ~> N ~> N) ctx base = Abs' (\c => snd . fst . c) stride : {c : Container} -> Term (W c ~> N ~> N) ctx stride = Abs' (\c => snd . c) calcIndex : Term (N ~> N ~> N ~> N) ctx calcIndex = AbsAll [<_,_,_] (\[ base + stride * n) reroot : {c : Container} -> Term (W c ~> N ~> W c) ctx reroot = AbsAll [<_,_] (\[ App Container.cons [ let base' = shift (App base [ App pair [ {c : Case} -> Term (semCase c (W cont) ~> N ~> N) ctx getFuel {c = (tag, 0)} = -- One tag in total Const (Const 1) getFuel {c = (tag, k@(S _))} = Abs' (\x => App Container.cons [ -- fuel (1 + i + k z) => fuel_i (z) -- The initial (1 +) is a consequence of the cons. let dm = App (divmod' k) [ {c : Case} -> Term (semCase c (W cont) ~> N ~> N) ctx getBase {c = (tag, 0)} = -- No children, so do not care Arb getBase {c = (tag, k@(S _))} = Abs' (\x => App Container.cons [<1 -- Children are 1, 2, ..., k , Abs' (\n => -- base (1 + i + k z) => 1 + i + k (base_i z) -- The initial (1 +) is a consequence of the cons. let dm = App (divmod' k) [ {c : Case} -> Term (semCase c (W cont) ~> N ~> N) ctx getStride {c = (tag, 0)} = -- No children, so do not care Arb getStride {c = (tag, k@(S _))} = Abs' (\x => App Container.cons [<1 -- Children are 1, 2, ..., k , Abs' (\n => -- stride (1 + i + k z) => k (stride_i z) -- The initial (1 +) is a consequence of the cons. let dm = App (divmod' k) [ {c : Case} -> (i : Elem c cont.constructors) -> Term (semCase c (W cont) ~> N ~> unitSem cont) ctx getVals i {c = (tag', 0)} = -- Only the root matters. Abs' (\x => Const $ App (tag @{mapNonEmpty cont.ok} (elemMap unitCase i) . forgetCase) [ App Container.cons [< -- Root is first App (tag @{mapNonEmpty cont.ok} (elemMap unitCase i) . forgetCase) [ -- vals (1 + i + k z) => vals_i (z) -- The initial (1 +) is a consequence of the cons let dm = App (divmod' k) [ {c : Case} -> (i : Elem c cont.constructors) -> Term (semCase c (W cont) ~> W cont) ctx introCase i = AbsAll [<_,_] (\[ App pair [ Term (sem c (W c) ~> W c) ctx intro = App (any @{mapNonEmpty c.ok}) {sty = map (~> W c) $ map (flip semCase (W c)) c.constructors} $ rewrite mapFusion (~> W c) (flip semCase (W c)) c.constructors in gtabulate introCase -- Case Splitting -------------------------------------------------------------- fillCase : {c : Case} -> {ty, ty' : Ty} -> Term ((Fin (snd c) ~> ty) ~> (semCase c ty ~> ty') ~> unitCase c ~> ty') ctx fillCase {c = (Just tag, k)} = Abs $ Abs $ Abs $ let f = Var (There $ There Here) in let sem = Var (There Here) in let val = Var Here in App sem [ {ty, ty' : Ty} -> Term (map (\c => semCase c ty ~> ty') c.constructors ~>* W c ~> (N ~> ty) ~> (N ~> ty')) ctx elimStep = AbsAll (_ :< _ :< _ :< _) -- fs: update action for each constructor -- x : fixed point -- f : initial value for each tag -- n : tag to compute at -- --- -- returns updated value for tag (\(fs :< x :< f :< n) => let val = App vals [ ty') (map unitCase c.constructors) :< unitSem c} $ rewrite mapFusion (~> ty') unitCase c.constructors in gtabulate (\i => Syntax.App fillCase [ semCase c ty ~> ty') i) fs ]) :< val) export inspect : {c : Container} -> {ty : Ty} -> Term (map (\c' => semCase c' (W c) ~> ty) c.constructors ~>* W c ~> ty) ctx inspect = AbsAll (_ :< _) (\(fs :< x) => App elimStep (fs :< x :< App reroot [ {ty : Ty} -> Term (map (\c => semCase c ty ~> ty) c.constructors ~>* W c ~> ty) ctx elim = AbsAll (_ :< _) (\(fs :< x) => App (Rec (App fuel [