on master help sign in
Make splitAt more efficient

Define Data.Vect.splitAt and Prelude.List.splitAt in terms of direct recursion instead of take and drop, which means the prefix only needs to be traversed once. Provide proofs that the new version is equivalent to the conceptually simpler take-drop version.

commit4d69b3f8096a1f65d66df0d5d09bda28b137abba authorhowtonotwin <rasheeqhere@gmail.com> dateSun 18 Mar 2018, 18:49 (9 years ago) parent8b6f86e
2 files changed+38−9
libs/base/Data/Vect.idr+18−4 libs/prelude/Prelude/List.idr+20−5
libs/base/Data/Vect.idr+18−4
@@ -321,6 +321,7 @@ foldr1 f (x::xs) = foldr f x xs
321321||| Foldl without seeding the accumulator
322322foldl1 : (t -> t -> t) -> Vect (S n) t -> t
323323foldl1 f (x::xs) = foldl f x xs
324+
324325--------------------------------------------------------------------------------
325326-- Scans
326327--------------------------------------------------------------------------------
@@ -455,13 +456,26 @@ delete = deleteBy (==)
455456-- Splitting and breaking lists
456457--------------------------------------------------------------------------------
457458
458−||| A tuple where the first element is a Vect of the n first elements and
459−||| the second element is a Vect of the remaining elements of the original Vect
460−||| It is equivalent to (take n xs, drop n xs)
459+||| A tuple where the first element is a `Vect` of the `n` first elements and
460+||| the second element is a `Vect` of the remaining elements of the original.
461+||| It is equivalent to `(take n xs, drop n xs)`, but is more efficient.
461462||| @ n the index to split at
462463||| @ xs the Vect to split in two
463464splitAt : (n : Nat) -> (xs : Vect (n + m) elem) -> (Vect n elem, Vect m elem)
464−splitAt n xs = (take n xs, drop n xs)
465+splitAt Z xs = ([], xs)
466+splitAt (S k) (x::xs) =
467+ let (tk, dr) = splitAt k xs
468+ in (x::tk, dr)
469+
470+splitAtTakeDrop : (n : Nat) -> (xs : Vect (n + m) a) -> splitAt n xs = (take n xs, drop n xs)
471+splitAtTakeDrop Z xs = Refl
472+splitAtTakeDrop (S k) (x::xs) with (splitAt k xs) proof p
473+ | (tk, dr) =
474+ let rec = sym $ trans p $ splitAtTakeDrop k xs
475+ tkp = cong {f=fst} rec
476+ drp = cong {f=snd} rec
477+ in replace {P = \tk' => (x::tk', dr) = (x::take k xs, drop k xs)} tkp $
478+ replace {P = \dr' => (x::take k xs, dr') = (x::take k xs, drop k xs) } drp Refl
465479
466480partition : (elem -> Bool) -> Vect len elem -> ((p ** Vect p elem), (q ** Vect q elem))
467481partition p [] = ((_ ** []), (_ ** []))
libs/prelude/Prelude/List.idr+20−5
@@ -675,13 +675,28 @@ split p xs =
675675 (chunk, []) => [chunk]
676676 (chunk, (c :: rest)) => chunk :: split p (assert_smaller xs rest)
677677
678−||| A tuple where the first element is a List of the n first elements and
679−||| the second element is a List of the remaining elements of the list
680−||| It is equivalent to (take n xs, drop n xs)
678+||| A tuple where the first element is a `List` of the `n` first elements and
679+||| the second element is a `List` of the remaining elements of the original.
680+||| It is equivalent to `(take n xs, drop n xs)`, but is more efficient.
681681||| @ n the index to split at
682−||| @ xs the list to split in two
682+||| @ xs the `List` to split in two
683683splitAt : (n : Nat) -> (xs : List a) -> (List a, List a)
684−splitAt n xs = (take n xs, drop n xs)
684+splitAt Z xs = ([], xs)
685+splitAt (S k) [] = ([], [])
686+splitAt (S k) (x::xs) =
687+ let (tk, dr) = splitAt k xs
688+ in (x::tk, dr)
689+
690+splitAtTakeDrop : (n : Nat) -> (xs : List a) -> splitAt n xs = (take n xs, drop n xs)
691+splitAtTakeDrop Z xs = Refl
692+splitAtTakeDrop (S k) [] = Refl
693+splitAtTakeDrop (S k) (x::xs) with (splitAt k xs) proof p
694+ | (tk, dr) =
695+ let rec = sym $ trans p $ splitAtTakeDrop k xs
696+ tkp = cong {f=fst} rec
697+ drp = cong {f=snd} rec
698+ in replace {P = \tk' => (x::tk', dr) = (x::take k xs, drop k xs)} tkp $
699+ replace {P = \dr' => (x::take k xs, dr') = (x::take k xs, drop k xs) } drp Refl
685700
686701||| The partition function takes a predicate a list and returns the pair of
687702||| lists of elements which do and do not satisfy the predicate, respectively;