2023-02-08 20:19:24 +03:00
|
|
|
||| The content of this module is based on the paper
|
|
|
|
||| A Type-Based Approach to Divide-And-Conquer Recursion in Coq
|
|
|
|
||| by Pedro Abreu, Benjamin Delaware, Alex Hubers, Christa Jenkins,
|
|
|
|
||| J. Garret Morris, and Aaron Stump
|
2023-07-05 18:42:58 +03:00
|
|
|
||| https://doi.org/10.1145/3571196
|
2023-02-08 20:19:24 +03:00
|
|
|
|||
|
|
|
|
||| The original paper relies on Coq's impredicative Set axiom,
|
|
|
|
||| something we don't have access to in Idris 2. We can however
|
|
|
|
||| reproduce the results by ignoring the type levels
|
|
|
|
|
|
|
|
module Control.DivideAndConquer
|
|
|
|
|
|
|
|
%default total
|
|
|
|
|
|
|
|
namespace Section4Sub1
|
|
|
|
|
|
|
|
public export
|
|
|
|
data ListF : (a, x : Type) -> Type where
|
|
|
|
Nil : ListF a x
|
|
|
|
(::) : a -> x -> ListF a x
|
|
|
|
|
|
|
|
lengthAlg : ListF a Nat -> Nat
|
|
|
|
lengthAlg [] = 0
|
|
|
|
lengthAlg (_ :: n) = S n
|
|
|
|
|
|
|
|
public export
|
|
|
|
Functor (ListF a) where
|
|
|
|
map f [] = []
|
|
|
|
map f (x :: xs) = x :: f xs
|
|
|
|
|
|
|
|
namespace Section6Sub1
|
|
|
|
|
|
|
|
public export
|
|
|
|
-- Only accepted because there is currently no universe check
|
|
|
|
data Mu : (Type -> Type) -> Type where
|
|
|
|
MkMu : forall r. (r -> Mu f) -> f r -> Mu f
|
|
|
|
|
|
|
|
public export
|
|
|
|
inMu : f (Mu f) -> Mu f
|
|
|
|
inMu = MkMu id
|
|
|
|
|
|
|
|
public export
|
|
|
|
outMu : Functor f => Mu f -> f (Mu f)
|
|
|
|
outMu (MkMu f d) = f <$> d
|
|
|
|
|
|
|
|
public export
|
|
|
|
fold : Functor f => (f a -> a) -> Mu f -> a
|
|
|
|
fold alg (MkMu f r) = alg (assert_total (fold alg . f <$> r))
|
|
|
|
|
|
|
|
namespace Section4Sub1
|
|
|
|
|
|
|
|
list : Type -> Type
|
|
|
|
list = Mu . ListF
|
|
|
|
|
|
|
|
namespace Smart
|
|
|
|
|
|
|
|
Nil : list a
|
|
|
|
Nil = inMu []
|
|
|
|
|
|
|
|
(::) : a -> list a -> list a
|
|
|
|
x :: xs = inMu (x :: xs)
|
|
|
|
|
|
|
|
fromList : List a -> list a
|
|
|
|
fromList = foldr (::) []
|
|
|
|
|
|
|
|
toList : list a -> List a
|
|
|
|
toList = fold $ \case
|
|
|
|
[] => []
|
|
|
|
(x :: xs) => x :: xs
|
|
|
|
|
|
|
|
namespace Section4Sub2
|
|
|
|
|
|
|
|
public export
|
|
|
|
KAlg : Type
|
|
|
|
KAlg = (Type -> Type) -> Type
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 Mono : (KAlg -> KAlg) -> Type
|
|
|
|
Mono f
|
|
|
|
= forall a, b.
|
|
|
|
(forall x. a x -> b x) ->
|
|
|
|
(forall x. f a x -> f b x)
|
|
|
|
|
|
|
|
public export
|
|
|
|
data Mu : (KAlg -> KAlg) -> KAlg where
|
|
|
|
MkMu : (forall x. a x -> Mu f x) ->
|
|
|
|
(forall x. f a x -> Mu f x)
|
|
|
|
|
|
|
|
public export
|
|
|
|
inMu : f (Mu f) x -> Mu f x
|
|
|
|
inMu = MkMu id
|
|
|
|
|
|
|
|
public export
|
|
|
|
outMu : Mono f -> Mu f x -> f (Mu f) x
|
|
|
|
outMu m (MkMu f d) = m f d
|
|
|
|
|
|
|
|
parameters (0 f : Type -> Type)
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 FoldT : KAlg -> Type -> Type
|
|
|
|
FoldT a r
|
|
|
|
= forall x.
|
|
|
|
Functor x =>
|
|
|
|
a x -> r -> x r
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 SAlgF : KAlg -> (Type -> Type) -> Type
|
|
|
|
SAlgF a x
|
|
|
|
= forall p, r.
|
|
|
|
(r -> p) ->
|
|
|
|
FoldT a r ->
|
|
|
|
(f r -> p) ->
|
|
|
|
(r -> x r) ->
|
|
|
|
f r -> x p
|
|
|
|
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 SAlg : (Type -> Type) -> Type
|
|
|
|
SAlg = Mu SAlgF
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 AlgF : KAlg -> (Type -> Type) -> Type
|
|
|
|
AlgF a x
|
|
|
|
= forall r.
|
|
|
|
FoldT a r ->
|
|
|
|
FoldT SAlg r ->
|
|
|
|
(r -> x r) ->
|
|
|
|
f r -> x r
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 Alg : (Type -> Type) -> Type
|
|
|
|
Alg = Mu AlgF
|
|
|
|
|
|
|
|
public export
|
|
|
|
inSAlg : SAlgF SAlg x -> SAlg x
|
|
|
|
inSAlg = inMu
|
|
|
|
|
|
|
|
public export
|
|
|
|
monoSAlgF : Mono SAlgF
|
|
|
|
monoSAlgF f salg up sfo = salg up (sfo . f)
|
|
|
|
|
|
|
|
public export
|
|
|
|
outSAlg : SAlg x -> SAlgF SAlg x
|
|
|
|
outSAlg = outMu monoSAlgF
|
|
|
|
|
|
|
|
public export
|
|
|
|
inAlg : AlgF Alg x -> Alg x
|
|
|
|
inAlg = inMu
|
|
|
|
|
|
|
|
public export
|
|
|
|
monoAlgF : Mono AlgF
|
|
|
|
monoAlgF f alg fo = alg (fo . f)
|
|
|
|
|
|
|
|
public export
|
|
|
|
outAlg : Alg x -> AlgF Alg x
|
|
|
|
outAlg = outMu monoAlgF
|
|
|
|
|
|
|
|
namespace Section6Sub2
|
|
|
|
|
|
|
|
parameters (0 f : Type -> Type)
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 DcF : Type -> Type
|
|
|
|
DcF a = forall x. Functor x => Alg f x -> x a
|
|
|
|
|
|
|
|
public export
|
|
|
|
functorDcF : Functor DcF
|
|
|
|
functorDcF = MkFunctor $ \ f, dc, alg => map f (dc alg)
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 Dc : Type
|
|
|
|
Dc = Mu DcF
|
|
|
|
|
|
|
|
public export
|
|
|
|
fold : FoldT f (Alg f) Dc
|
|
|
|
fold alg dc = outMu @{functorDcF} dc alg
|
|
|
|
|
|
|
|
public export
|
|
|
|
record RevealT (x : Type -> Type) (r : Type) where
|
|
|
|
constructor MkRevealT
|
|
|
|
runRevealT : (r -> Dc) -> x Dc
|
|
|
|
|
|
|
|
public export %hint
|
|
|
|
functorRevealT : Functor (RevealT x)
|
|
|
|
functorRevealT = MkFunctor $ \ f, t =>
|
|
|
|
MkRevealT (\ g => runRevealT t (g . f))
|
|
|
|
|
|
|
|
public export
|
|
|
|
promote : Functor x => SAlg f x -> Alg f (RevealT x)
|
|
|
|
promote salg
|
|
|
|
= inAlg f $ \ fo, sfo, rec, fr =>
|
|
|
|
MkRevealT $ \ reveal =>
|
|
|
|
let abstIn := \ fr => inMu (\ alg => reveal <$> outAlg f alg fo sfo (fo alg) fr) in
|
|
|
|
outSAlg f salg reveal sfo abstIn (sfo salg) fr
|
|
|
|
|
|
|
|
public export
|
|
|
|
sfold : FoldT f (SAlg f) Dc
|
|
|
|
sfold salg dc = runRevealT (fold (promote salg) dc) id
|
|
|
|
|
|
|
|
public export
|
|
|
|
inDc : f Dc -> Dc
|
|
|
|
inDc d = inMu (\ alg => outAlg f alg fold sfold (fold alg) d)
|
|
|
|
|
|
|
|
out : Functor f => FoldT f (SAlg f) r -> r -> f r
|
|
|
|
out sfo = sfo (inSAlg f (\ up, _, _, _ => map up))
|
|
|
|
|
|
|
|
namespace Section5Sub1
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 list : Type -> Type
|
|
|
|
list a = Dc (ListF a)
|
|
|
|
|
|
|
|
namespace Smart
|
|
|
|
|
|
|
|
public export
|
|
|
|
Nil : list a
|
|
|
|
Nil = inDc (ListF a) []
|
|
|
|
|
|
|
|
public export
|
|
|
|
(::) : a -> list a -> list a
|
|
|
|
x :: xs = inDc (ListF a) (x :: xs)
|
|
|
|
|
|
|
|
public export
|
|
|
|
fromList : List a -> list a
|
|
|
|
fromList = foldr (::) []
|
|
|
|
|
|
|
|
public export
|
|
|
|
0 SpanF : Type -> Type -> Type
|
|
|
|
SpanF a x = (List a, x)
|
|
|
|
|
|
|
|
SpanSAlg : (a -> Bool) -> SAlg (ListF a) (SpanF a)
|
|
|
|
SpanSAlg p = inSAlg (ListF a) $ \up, sfo, abstIn, span, xs =>
|
|
|
|
case xs of
|
|
|
|
[] => ([], abstIn xs)
|
|
|
|
(x :: xs') =>
|
|
|
|
if p x
|
|
|
|
then let (r, s) = span xs' in (x :: r, up s)
|
|
|
|
else ([], abstIn xs)
|
|
|
|
|
|
|
|
export
|
|
|
|
spanr : FoldT (ListF a) (SAlg (ListF a)) r ->
|
|
|
|
(a -> Bool) -> (xs : r) -> SpanF a r
|
|
|
|
spanr sfo p xs = sfo (SpanSAlg p) @{MkFunctor mapSnd} xs
|
|
|
|
|
|
|
|
breakr : FoldT (ListF a) (SAlg (ListF a)) r ->
|
|
|
|
(a -> Bool) -> (xs : r) -> SpanF a r
|
|
|
|
breakr sfo p = spanr sfo (not . p)
|
|
|
|
|
|
|
|
WordsByAlg : (a -> Bool) -> Alg (ListF a) (const (List (List a)))
|
|
|
|
WordsByAlg p = inAlg (ListF a) $ \ fo, sfo, wordsBy, xs =>
|
|
|
|
case xs of
|
|
|
|
[] => []
|
|
|
|
(hd :: tl) =>
|
|
|
|
if p hd
|
|
|
|
then wordsBy tl
|
|
|
|
else
|
|
|
|
let (w, rest) = breakr sfo p tl in
|
|
|
|
(hd :: w) :: wordsBy rest
|
|
|
|
|
|
|
|
wordsBy : (a -> Bool) -> (xs : List a) -> List (List a)
|
|
|
|
wordsBy p = fold (ListF a) @{MkFunctor (const id)} (WordsByAlg p) . fromList
|
|
|
|
|
|
|
|
namespace Section5Sub3
|
|
|
|
|
|
|
|
data NatF x = Z | S x
|
|
|
|
|
|
|
|
0 nat : Type
|
|
|
|
nat = Dc NatF
|
|
|
|
|
|
|
|
fromNat : Nat -> Section5Sub3.nat
|
|
|
|
fromNat Z = inDc NatF Z
|
|
|
|
fromNat (S n) = inDc NatF (S (fromNat n))
|
|
|
|
|
|
|
|
toNat : Section5Sub3.nat -> Nat
|
|
|
|
toNat = fold NatF @{MkFunctor (const id)} idAlg where
|
|
|
|
|
|
|
|
idAlg : Alg NatF (const Nat)
|
|
|
|
idAlg = inAlg NatF $ \ fo, sfo, toNat, n =>
|
|
|
|
case n of
|
|
|
|
Z => Z
|
|
|
|
S n' => S (toNat n')
|
|
|
|
|
|
|
|
zeroSAlg : SAlg NatF Prelude.id
|
|
|
|
zeroSAlg = inSAlg NatF $ \ up, sfo, abstIn, zero, n =>
|
|
|
|
case n of
|
|
|
|
Z => abstIn n
|
|
|
|
S p => up (zero (zero p))
|
|
|
|
|
|
|
|
export
|
|
|
|
zero : Nat -> Nat
|
|
|
|
zero = toNat . sfold NatF @{MkFunctor id} zeroSAlg . fromNat
|
|
|
|
|
|
|
|
namespace Section5Sub3
|
|
|
|
|
|
|
|
data TreeF a x = Node a (List x)
|
|
|
|
|
|
|
|
0 tree : Type -> Type
|
|
|
|
tree a = Dc (TreeF a)
|
|
|
|
|
|
|
|
node : a -> List (tree a) -> tree a
|
|
|
|
node n ts = inDc (TreeF a) (Node n ts)
|
|
|
|
|
|
|
|
mirrorAlg : SAlg (TreeF a) Prelude.id
|
|
|
|
mirrorAlg = inSAlg (TreeF a) $ \ up, sfo, abstIn, mirror, t =>
|
|
|
|
case t of Node a ts => abstIn (Node a $ map mirror (reverse ts))
|
|
|
|
|
|
|
|
mirror : tree a -> tree a
|
|
|
|
mirror = sfold (TreeF a) @{MkFunctor id} mirrorAlg
|
|
|
|
|
|
|
|
namespace Section5Sub4
|
|
|
|
|
|
|
|
0 MappedT : (a, b : Type) -> Type
|
|
|
|
MappedT a b = forall r. FoldT (ListF a) (SAlg (ListF a)) r -> a -> r -> (b, r)
|
|
|
|
|
|
|
|
MapThroughAlg : MappedT a b -> Alg (ListF a) (const (List b))
|
|
|
|
MapThroughAlg f = inAlg (ListF a) $ \fo, sfo, mapThrough, xs =>
|
|
|
|
case xs of
|
|
|
|
[] => []
|
|
|
|
hd :: tl =>
|
|
|
|
let (b, rest) = f sfo hd tl in
|
|
|
|
b :: mapThrough rest
|
|
|
|
|
|
|
|
mapThrough : MappedT a b -> list a -> List b
|
|
|
|
mapThrough f = fold (ListF a) (MapThroughAlg f) @{MkFunctor (const id)}
|
|
|
|
|
|
|
|
compressSpan : Eq a => MappedT a (Nat, a)
|
|
|
|
compressSpan sfo hd tl
|
|
|
|
= let (pref, rest) = spanr sfo (hd ==) tl in
|
|
|
|
((S (length pref), hd), rest)
|
|
|
|
|
|
|
|
runLengthEncoding : Eq a => List a -> List (Nat, a)
|
|
|
|
runLengthEncoding = mapThrough compressSpan . fromList
|
|
|
|
|
|
|
|
namespace Section5Sub5
|
|
|
|
|
|
|
|
K : Type -> Type
|
|
|
|
K t = t -> Bool
|
|
|
|
|
|
|
|
MatchT : Type -> Type
|
|
|
|
MatchT t = K t -> Bool
|
|
|
|
|
|
|
|
data Regex = Zero | Exact Char | Sum Regex Regex | Cat Regex Regex | Plus Regex
|
|
|
|
|
|
|
|
matchi : (t -> Regex -> MatchT t) -> Regex -> Char -> t -> MatchT t
|
|
|
|
matchi matcher Zero c cs k = False
|
|
|
|
matchi matcher (Exact c') c cs k = (c == c') && k cs
|
|
|
|
matchi matcher (Sum r1 r2) c cs k = matchi matcher r1 c cs k || matchi matcher r2 c cs k
|
|
|
|
matchi matcher (Cat r1 r2) c cs k = matchi matcher r1 c cs (\ cs => matcher cs r2 k)
|
|
|
|
matchi matcher (Plus r) c cs k = matchi matcher r c cs (\ cs => k cs || matcher cs (Plus r) k)
|
|
|
|
|
|
|
|
MatcherF : Type -> Type
|
|
|
|
MatcherF t = Regex -> MatchT t
|
|
|
|
|
|
|
|
functorMatcherF : Functor MatcherF
|
|
|
|
functorMatcherF = MkFunctor (\ f, t, r, p => t r (p . f))
|
|
|
|
|
|
|
|
MatcherAlg : Alg (ListF Char) MatcherF
|
|
|
|
MatcherAlg = inAlg (ListF Char) $ \ fo, sfo, matcher, s =>
|
|
|
|
case s of
|
|
|
|
[] => \ r, k => False
|
|
|
|
(c :: cs) => \ r => matchi matcher r c cs
|
|
|
|
|
|
|
|
match : Regex -> String -> Bool
|
|
|
|
match r str = fold (ListF Char) MatcherAlg @{functorMatcherF} chars r isNil
|
|
|
|
|
|
|
|
where
|
|
|
|
isNil : Mu (DcF (ListF Char)) -> Bool
|
|
|
|
isNil = fold (ListF Char) {x = const Bool} @{MkFunctor (const id)}
|
|
|
|
$ inAlg (ListF Char)
|
|
|
|
$ \fo, sfo, rec, xs => case xs of
|
|
|
|
Nil => True
|
|
|
|
(_ :: _) => False
|
|
|
|
|
|
|
|
chars : Mu (DcF (ListF Char))
|
|
|
|
chars = fromList (unpack str)
|
|
|
|
|
|
|
|
export
|
|
|
|
matchExample : Bool
|
|
|
|
matchExample = match (Plus $ Cat (Sum (Exact 'a') (Exact 'b')) (Exact 'a')) "aabaaaba"
|
|
|
|
|
|
|
|
namespace Section5Sub6
|
|
|
|
|
|
|
|
parameters {0 a : Type} (ltA : a -> a -> Bool)
|
|
|
|
|
|
|
|
0 PartF : Type -> Type
|
|
|
|
PartF x = a -> (x, x)
|
|
|
|
|
|
|
|
PartSAlg : SAlg (ListF a) PartF
|
|
|
|
PartSAlg = inSAlg (ListF a) $ \up, sfo, abstIn, partition, d, pivot => case d of
|
|
|
|
[] => let xs = abstIn d in (xs, xs)
|
|
|
|
x :: xs => let (l, r) = partition xs pivot in
|
|
|
|
if ltA x pivot then (abstIn (x :: l), up r)
|
|
|
|
else (up l, abstIn (x :: r))
|
|
|
|
|
|
|
|
partr : (sfo : FoldT (ListF a) (SAlg (ListF a)) r) -> r -> a -> (r, r)
|
|
|
|
partr sfo = sfo @{MkFunctor $ \ f, p, x => bimap f f (p x)} PartSAlg
|
|
|
|
|
|
|
|
QuickSortAlg : Alg (ListF a) (const (List a))
|
|
|
|
QuickSortAlg = inAlg (ListF a) $ \ fo, sfo, qsort, xs => case xs of
|
|
|
|
[] => []
|
|
|
|
p :: xs => let (l, r) = partr sfo xs p in
|
|
|
|
qsort l ++ p :: qsort r
|
|
|
|
|
|
|
|
quicksort : List a -> List a
|
|
|
|
quicksort = fold (ListF a) QuickSortAlg @{MkFunctor (const id)} . fromList
|
|
|
|
|
|
|
|
export
|
|
|
|
sortExample : String -> String
|
|
|
|
sortExample = pack . quicksort (<=) . unpack
|