adamc@5: (* Copyright (c) 2008, Adam Chlipala adamc@5: * All rights reserved. adamc@5: * adamc@5: * Redistribution and use in source and binary forms, with or without adamc@5: * modification, are permitted provided that the following conditions are met: adamc@5: * adamc@5: * - Redistributions of source code must retain the above copyright notice, adamc@5: * this list of conditions and the following disclaimer. adamc@5: * - Redistributions in binary form must reproduce the above copyright notice, adamc@5: * this list of conditions and the following disclaimer in the documentation adamc@5: * and/or other materials provided with the distribution. adamc@5: * - The names of contributors may not be used to endorse or promote products adamc@5: * derived from this software without specific prior written permission. adamc@5: * adamc@5: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" adamc@5: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE adamc@5: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE adamc@5: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE adamc@5: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR adamc@5: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF adamc@5: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS adamc@5: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN adamc@5: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) adamc@5: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE adamc@5: * POSSIBILITY OF SUCH DAMAGE. adamc@5: *) adamc@5: adamc@5: structure ListUtil :> LIST_UTIL = struct adamc@5: adamc@6: structure S = Search adamc@6: adamc@110: fun mapConcat f = adamc@110: let adamc@110: fun mc acc ls = adamc@110: case ls of adamc@110: [] => rev acc adamc@110: | h :: t => mc (List.revAppend (f h, acc)) t adamc@110: in adamc@110: mc [] adamc@110: end adamc@110: adamc@6: fun mapfold f = adamc@6: let adamc@6: fun mf ls s = adamc@6: case ls of adamc@6: nil => S.Continue (nil, s) adamc@6: | h :: t => adamc@6: case f h s of adamc@6: S.Return x => S.Return x adamc@6: | S.Continue (h', s) => adamc@6: case mf t s of adamc@6: S.Return x => S.Return x adamc@6: | S.Continue (t', s) => S.Continue (h' :: t', s) adamc@6: in adamc@6: mf adamc@6: end adamc@6: adamc@34: fun mapfoldB f = adamc@34: let adamc@34: fun mf ctx ls s = adamc@34: case ls of adamc@34: nil => S.Continue (nil, s) adamc@34: | h :: t => adamc@34: let adamc@34: val (ctx, r) = f (ctx, h) adamc@34: in adamc@34: case r s of adamc@34: S.Return x => S.Return x adamc@34: | S.Continue (h', s) => adamc@34: case mf ctx t s of adamc@34: S.Return x => S.Return x adamc@34: | S.Continue (t', s) => S.Continue (h' :: t', s) adamc@34: end adamc@34: in adamc@34: mf adamc@34: end adamc@34: adamc@26: fun foldlMap f s = adamc@26: let adamc@26: fun fm (ls', s) ls = adamc@26: case ls of adamc@26: nil => (rev ls', s) adamc@26: | h :: t => adamc@26: let adamc@26: val (h', s') = f (h, s) adamc@26: in adamc@26: fm (h' :: ls', s') t adamc@26: end adamc@26: in adamc@26: fm ([], s) adamc@26: end adamc@26: adamc@39: fun foldlMapConcat f s = adamc@39: let adamc@39: fun fm (ls', s) ls = adamc@39: case ls of adamc@39: nil => (rev ls', s) adamc@39: | h :: t => adamc@39: let adamc@39: val (h', s') = f (h, s) adamc@39: in adamc@39: fm (List.revAppend (h', ls'), s') t adamc@39: end adamc@39: in adamc@39: fm ([], s) adamc@39: end adamc@39: adamc@39: fun foldlMapPartial f s = adamc@39: let adamc@39: fun fm (ls', s) ls = adamc@39: case ls of adamc@39: nil => (rev ls', s) adamc@39: | h :: t => adamc@39: let adamc@39: val (h', s') = f (h, s) adamc@39: val ls' = case h' of adamc@39: NONE => ls' adamc@39: | SOME h' => h' :: ls' adamc@39: in adamc@39: fm (ls', s') t adamc@39: end adamc@39: in adamc@39: fm ([], s) adamc@39: end adamc@39: adamc@849: fun foldlMapiPartial f s = adamc@849: let adamc@849: fun fm (n, ls', s) ls = adamc@849: case ls of adamc@849: nil => (rev ls', s) adamc@849: | h :: t => adamc@849: let adamc@849: val (h', s') = f (n, h, s) adamc@849: val ls' = case h' of adamc@849: NONE => ls' adamc@849: | SOME h' => h' :: ls' adamc@849: in adamc@849: fm (n + 1, ls', s') t adamc@849: end adamc@849: in adamc@849: fm (0, [], s) adamc@849: end adamc@849: adamc@847: fun foldlMapAbort f s = adamc@847: let adamc@847: fun fm (ls', s) ls = adamc@847: case ls of adamc@847: nil => SOME (rev ls', s) adamc@847: | h :: t => adamc@847: case f (h, s) of adamc@847: NONE => NONE adamc@847: | SOME (h', s') => fm (h' :: ls', s') t adamc@847: in adamc@847: fm ([], s) adamc@847: end adamc@847: adamc@23: fun search f = adamc@23: let adamc@23: fun s ls = adamc@23: case ls of adamc@23: [] => NONE adamc@23: | h :: t => adamc@23: case f h of adamc@23: NONE => s t adamc@23: | v => v adamc@23: in adamc@23: s adamc@23: end adamc@23: adamc@839: fun searchi f = adamc@839: let adamc@839: fun s n ls = adamc@839: case ls of adamc@839: [] => NONE adamc@839: | h :: t => adamc@839: case f (n, h) of adamc@839: NONE => s (n + 1) t adamc@839: | v => v adamc@839: in adamc@839: s 0 adamc@839: end adamc@839: adamc@120: fun mapi f = adamc@120: let adamc@120: fun m i acc ls = adamc@120: case ls of adamc@120: [] => rev acc adamc@120: | h :: t => m (i + 1) (f (i, h) :: acc) t adamc@120: in adamc@120: m 0 [] adamc@120: end adamc@120: adamc@849: fun mapiPartial f = adamc@849: let adamc@849: fun m i acc ls = adamc@849: case ls of adamc@849: [] => rev acc adamc@849: | h :: t => adamc@849: m (i + 1) (case f (i, h) of adamc@849: NONE => acc adamc@849: | SOME v => v :: acc) t adamc@849: in adamc@849: m 0 [] adamc@849: end adamc@849: adamc@792: fun appi f = adamc@792: let adamc@792: fun m i ls = adamc@792: case ls of adamc@792: [] => () adamc@792: | h :: t => (f (i, h); m (i + 1) t) adamc@792: in adamc@792: m 0 adamc@792: end adamc@792: adamc@191: fun foldli f = adamc@191: let adamc@191: fun m i acc ls = adamc@191: case ls of adamc@191: [] => acc adamc@191: | h :: t => m (i + 1) (f (i, h, acc)) t adamc@191: in adamc@191: m 0 adamc@191: end adamc@191: adamc@275: fun foldri f i ls = adamc@275: let adamc@275: val len = length ls adamc@275: in adamc@275: foldli (fn (n, x, s) => f (len - n - 1, x, s)) i (rev ls) adamc@275: end adamc@275: adamc@313: fun foldliMap f s = adamc@313: let adamc@313: fun fm (n, ls', s) ls = adamc@313: case ls of adamc@313: nil => (rev ls', s) adamc@313: | h :: t => adamc@313: let adamc@313: val (h', s') = f (n, h, s) adamc@313: in adamc@313: fm (n + 1, h' :: ls', s') t adamc@313: end adamc@313: in adamc@313: fm (0, [], s) adamc@313: end adamc@313: adamc@792: fun appn f n = adamc@792: let adamc@792: fun iter m = adamc@792: if m >= n then adamc@792: () adamc@792: else adamc@792: (f m; adamc@792: iter (m + 1)) adamc@792: in adamc@792: iter 0 adamc@792: end adamc@792: adamc@5: end