0 | ||| A module defining the dependent list and its interface
  1 | module Data.DList
  2 |
  3 | import Data.Singleton
  4 | import Data.DSum
  5 | import Data.Some
  6 |
  7 | ||| A dependent list
  8 | ||| @ f  the constructor of the types of elements
  9 | ||| @ ts the partameters from which the types of the lists elements are
 10 | |||      constructed
 11 | public export
 12 | data DList : (f : a -> Type) -> (ts : List a) -> Type where
 13 |   ||| The empty dependent list
 14 |   Nil : DList f Nil
 15 |   ||| Prepends a dependently typed element to a dependent list
 16 |   (::) : {0 x : a} -> f x -> DList f xs -> DList f (x :: xs)
 17 |
 18 | -- Basic utils ----------------------------------------------------------------
 19 |
 20 | ||| Concatenate two dependent lists
 21 | public export
 22 | (++) : DList f xs -> DList f ys -> DList f (xs ++ ys)
 23 | Nil         ++ fys = fys
 24 | (fx :: fxs) ++ fys = fx :: fxs ++ fys
 25 |
 26 | ||| Return the length of a dependent list
 27 | export
 28 | length : DList f xs -> Nat
 29 | length Nil = Z
 30 | length (x :: xs) = S (length xs)
 31 |
 32 | ||| The head of a dependent list
 33 | export
 34 | head : DList f (x :: xs) -> f x
 35 | head (fx :: fxs) = fx
 36 |
 37 | ||| The tail of a dependent list
 38 | export
 39 | tail : DList f (x :: xs) -> DList f xs
 40 | tail (fx :: fxs) = fxs
 41 |
 42 | ||| split a dependent list in two
 43 | export
 44 | split : {xs, xs' : List a} -> DList f (xs ++ xs') -> (DList f xs, DList f xs')
 45 | split {xs = Nil} dl = (Nil, dl)
 46 | split {xs = x :: xs''} (fx :: fxs''') = let (fxs'', fxs') = split (fxs''') in (fx :: fxs'', fxs')
 47 |
 48 | -- ? --------------------------------------------------------------------------
 49 |
 50 | ||| Push a component of the element type constructor to the parameter list
 51 | export
 52 | pushToParams : DList (f . g) ts -> DList f (map g ts)
 53 | -- Using `believe_me` to avoid pattern matching,
 54 | -- taking advantage from the fact that `List` and `DList` are
 55 | -- representationally equal
 56 | --
 57 | -- TODO: try implement `DList` as an alias for `HList`,
 58 | -- then you could use `id` in place of `believe_me`
 59 | pushToParams xs = believe_me xs
 60 |
 61 | ||| Pull a component of the element type constructor from the parameter list
 62 | export
 63 | pullFromParams : DList f (map g ts) -> DList (f . g) ts
 64 | -- Using `believe_me` to avoid pattern matching,
 65 | -- taking advantage from the fact that `List` and `DList` are
 66 | -- representationally equal
 67 | pullFromParams xs = believe_me xs
 68 |
 69 | -- Mapping --------------------------------------------------------------------
 70 |
 71 | ||| Apply a function to every element of a dependent list
 72 | export
 73 | dmap : ({0 x : t} -> a x -> b x) -> DList a xs -> DList b xs
 74 | dmap f Nil = Nil
 75 | dmap f (ax :: axs) = f ax :: dmap f axs
 76 |
 77 | ||| Turn a dependent list into a non-dependent one by applying a
 78 | ||| dependency-removing function to its elements.
 79 | export
 80 | undmap : ({0 x : t} -> a x -> b) -> DList a xs -> List b
 81 | undmap f Nil = Nil
 82 | undmap f (ax :: axs) = f ax :: undmap f axs
 83 |
 84 | ||| Apply a dependent function to every element of a list,
 85 | ||| thus, generate a dependent list
 86 | export
 87 | dmapList : ((x : t) -> f x) -> (xs : List t) -> DList f xs
 88 | dmapList g Nil = Nil
 89 | dmapList g (x :: xs) = g x :: dmapList g xs
 90 |
 91 | ||| A more general version of `dmapList`, where the resulting list is dependent
 92 | ||| on a list of parameters which is itself a mapping on the original list
 93 | export
 94 | dmapList'
 95 |    : (0 f : a -> b)
 96 |   -> ((x : a) -> g (f x))
 97 |   -> (xs : List a)
 98 |   -> DList g (map f xs)
 99 | dmapList' f gg xs = pushToParams (dmapList gg xs)
100 |
101 | -- Traversing -----------------------------------------------------------------
102 |
103 | -- TODO: rewrite in terms of `Applicative`
104 | ||| Dependent version of `traverse`.
105 | |||
106 | ||| Map each element of a dependent list to a computation, evaluate those
107 | ||| computations and combine the results.
108 | export
109 | dtraverse
110 |    : Monad f
111 |   => {0 t : Type}
112 |   -> {0 a, b : t -> Type}
113 |   -> {0 xs : List t}
114 |
115 |   -> ({0 x : t} -> a x -> f (b x))
116 |   -> DList a xs
117 |   -> f (DList b xs)
118 |
119 | dtraverse f Nil = pure Nil
120 | dtraverse f (ax :: axs) = do
121 |   bx <- f ax
122 |   bxs <- dtraverse f axs
123 |
124 |   pure (bx :: bxs)
125 |
126 | -- TODO: rewrite in terms of `Applicative`
127 | ||| Map each element of a list to a computation whose result type is dependent
128 | ||| on the element, evaluate those computations and combine the results.
129 | export
130 | dtraverseList
131 |    : Monad m
132 |   => {0 a : Type}
133 |   -> {0 g : a -> Type}
134 |
135 |   -> ((x : a) -> m (g x))
136 |   -> (xs : List a)
137 |   -> m (DList g xs)
138 |
139 | dtraverseList f xs = dtraverse (\(Val x) => f x) (dmapList Val xs)
140 | -- This also works but I am uncomfortable with it because it creates a list of
141 | -- "computations" (`replicate xs f`)
142 | --dtraverseList f xs = dtraverse id (replicate xs f)
143 |
144 | -- Folding --------------------------------------------------------------------
145 |
146 | ||| `foldr` version for dependent lists
147 | export
148 | dfoldr : ({0 x : t} -> el x -> acc -> acc) -> acc -> DList el ts -> acc
149 | dfoldr f acc Nil = acc
150 | dfoldr f acc (x :: xs) = f x $ dfoldr f acc xs
151 |
152 | ||| `foldl` version for dependent lists
153 | export
154 | dfoldl : ({0 x : t} -> acc -> el x -> acc) -> acc -> DList el ts -> acc
155 | dfoldl f acc Nil = acc
156 | dfoldl f acc (x :: xs) = dfoldl f (f acc x) xs
157 |
158 | -- Zipping --------------------------------------------------------------------
159 |
160 | ||| `unzipWith` for dependent lists
161 | export
162 | dunzipWith
163 |    : ({0 x : t} -> f x -> (g x, h x))
164 |   -> (DList f xs)
165 |   -> (DList g xs, DList h xs)
166 | dunzipWith func Nil = (Nil, Nil)
167 | dunzipWith func (fx :: fxs) = let
168 |   (gx, hx) = func fx
169 |   (gxs, hxs) = dunzipWith func fxs
170 |   in (gx :: gxs, hx :: hxs)
171 |
172 | ||| `unzip` for dependent lists
173 | export
174 | dunzip
175 |    : DList (\x => (f x, g x)) xs
176 |   -> (DList f xs, DList g xs)
177 | dunzip = dunzipWith id
178 |
179 | ||| `zipWith` for dependent lists
180 | export
181 | dzipWith
182 |    : ({0 x : t} -> f x -> g x -> h x)
183 |   -> DList f xs
184 |   -> DList g xs
185 |   -> DList h xs
186 | dzipWith func Nil Nil = Nil
187 | dzipWith func (fx :: fxs) (gx :: gxs) = (func fx gx) :: dzipWith func fxs gxs
188 |
189 | ||| `zip` for dependent lists
190 | export
191 | dzip
192 |    : DList f xs
193 |   -> DList g xs
194 |   -> DList (\x => (f x, g x)) xs
195 | dzip = dzipWith (,)
196 |
197 | ||| Unzip a list to a dependent list and its parameter list, using a function
198 | ||| that returns a dependent pair
199 | export
200 | unzipParamsWith
201 |    : {0 f : b -> Type}
202 |   -> (a -> (y ** f y))
203 |   -> List a
204 |   -> (ys ** DList f ys)
205 | unzipParamsWith g Nil = (Nil ** Nil)
206 | unzipParamsWith g (x :: xs) = let
207 |     (y ** fy= g x
208 |     (ys ** fys= unzipParamsWith g xs
209 |   in (y :: ys ** fy :: fys)
210 |
211 | ||| Unzip a list of dependent pairs
212 | ||| Returns a list of parameters and a list of the dependent elements
213 | export
214 | unzipParams
215 |    : {0 f : a -> Type}
216 |   -> (dpairs : List (x ** f x))
217 |   -> (xs ** DList f xs)
218 | unzipParams = unzipParamsWith id
219 |
220 | ||| Zip a dependent list with its params, according to a zipping function
221 | export
222 | zipParamsWith
223 |    : {0 f : b -> Type}
224 |   -> ((y : b) -> f y -> a)
225 |   -> (ys ** DList f ys)
226 |   -> List a
227 | zipParamsWith g (Nil ** Nil= Nil
228 | zipParamsWith g (y :: ys ** fy :: fys= let
229 |     x = g y fy
230 |     xs = zipParamsWith g (ys ** fys)
231 |   in (x :: xs)
232 |
233 | ||| Zip a dependent list with its params
234 | export
235 | zipParams : {0 f : b -> Type} -> (ys ** DList f ys-> List (y ** f y)
236 | zipParams dpairs = zipParamsWith (\y => \fy => (y ** fy)) dpairs
237 |
238 | ||| Unzip a list of dependent sums
239 | export
240 | unzipDSums : List (DSum f g) -> (Some (DList f), Some (DList g))
241 | unzipDSums Nil = (MkSome Nil, MkSome Nil)
242 | unzipDSums ((fx :=> gx) :: dsums) = let
243 |   (MkSome fxs, MkSome gxs) = unzipDSums dsums
244 |   in (MkSome (fx :: fxs), MkSome (gx :: gxs))
245 |
246 | ||| Zip two dependent lists into a list of dependent sums
247 | export
248 | zipToDSums : DList f xs -> DList g xs -> List (DSum f g)
249 | zipToDSums xs ys = undmap id (dzipWith (:=>) xs ys {h = const (DSum f g)})
250 |
251 | ||| Zip a list of dependent pairs with an un-zipping function
252 | export
253 | unzipDPairsWith
254 |    : {0 f, g, h : t -> Type}
255 |   -> ({0 x : t} -> f x -> (g x, h x))
256 |   -> (dpairs : List (x : t ** (f x)))
257 |   -> (DList g (map DPair.fst dpairs), DList h (map DPair.fst dpairs))
258 | unzipDPairsWith func Nil = (Nil, Nil)
259 | unzipDPairsWith func ((x ** fx:: dpairs) = let
260 |   (gx, hx) = func fx
261 |   (gxs, hxs) = unzipDPairsWith func dpairs
262 |   in (gx :: gxs, hx :: hxs)
263 |
264 | ||| Zip a list of dependent pairs
265 | ||| (of pairs of elements dependent on a common parameter)
266 | export
267 | unzipDPairs
268 |    : (dpairs : List (x : t ** (f x, g x)))
269 |   -> (DList f (map DPair.fst dpairs), DList g (map DPair.fst dpairs))
270 | unzipDPairs xs = unzipDPairsWith id xs
271 |
272 | ||| Zip two dependent lists into a list of dependent pairs, according to a
273 | ||| zipping function
274 | export
275 | zipToDPairsWith
276 |    : {xs : List t}
277 |   -> {0 f, g, h : t -> Type}
278 |   -> ({0 x : t} -> f x -> g x -> h x)
279 |   -> DList f xs
280 |   -> DList g xs
281 |   -> List (x : t ** h x)
282 | zipToDPairsWith {xs} func fxs gxs = zipParams (xs ** dzipWith func fxs gxs)
283 |
284 | ||| Zip two dependent lists into a list of dependent pairs
285 | ||| (of pairs of elements dependent on a common parameter)
286 | export
287 | zipToDPairs
288 |    : {xs : List t}
289 |   -> DList f xs
290 |   -> DList g xs
291 |   -> List (x : t ** (f x, g x))
292 | zipToDPairs = zipToDPairsWith (,)
293 |