
Dear Cafe - what is the ordering of the output of https://hackage.haskell.org/package/base-4.16.0.0/docs/src/Data.OldList.html... - and why is it not lexicographic? E.g., *Main> last $ L.permutations [1..8] [5,3,6,2,7,1,8,4] note: [5,_,6,_,7,_,8,_] and [_,3,_,2,_,1,_,4] indeed, an auxiliary function is called "interleave". Data.List.permutations appeared in base-4.0.0.0 (ghc-6.10.1, 2008) https://downloads.haskell.org/~ghc/6.10.1/docs/html/users_guide/release-6-10... What is the source of the algorithm? Is it any of the algorithms in Knuth AOCP 4A(I) 7.2.1.2? Hard to tell - as they are given in an imperative style. The implementation *is* fast, e.g., L.sort . L.permutations seems better than a naive lexicographic enumeration lp1 [] = [[]] lp1 xs = do (ys, z:zs) <- zip (L.inits xs) (L.tails xs) (z:) <$> lp1 (ys <> zs) (un-scientifically measured with :set +s) Here, clearly, L.inits and "<>" are bad. NB - I was looking in to this because of https://www.mathekalender.de/wp/calendar/challenges/challenge-01/ Yes I know that can be solved without enumeration. - J.

what is the ordering of the output of https://hackage.haskell.org/package/base-4.16.0.0/docs/src/Data.OldList.html... - and why is it not lexicographic?
OK I think I know what's happening. 1. This function works on infinite lists: it will permute finite prefixes, in increasing length, while keeping the infinite suffix. map (take 5) $ take 3 $ permutations [1 .. ] -- infinite! [[1,2,3,4,5],[2,1,3,4,5],[3,2,1,4,5]] This specification is incompatible with lexicographic order. We could aim for inverse-lexicographic decrease (i.e., `reverse $ map reverse $ permutations xs` is increasing) but currently, it's not. 2. The program is equivalent (try it!) to permutations xs0 = xs0 : do (is', t:ts) <- splits xs0 xs <- permutations $ reverse is' -- reverse not needed, see below (pre, p:ost) <- splits xs return $ pre <> (t : p : ost <> ts) with this auxiliary function (that I sometimes wish was in Data.List) splits xs = zip (inits xs) (tails xs) splits "bar" = [("","bar"),("b","ar"),("ba","r"),("bar","")] That is the form of the program that I have a chance to understand, and prove correct. But - 3. This program contains several "append" (<>). Some are visible, some are hidden in the do notation (?), and in Data.List.inits. A series of uglification steps now transforms each "append" into a function with an extra accumulating parameter, and fuses some of these function calls. E.g., "interleave" (from the source code) is actually this function interleave t ts xs r = ( map (<> ts) $ do (pre, p:ost) <- splits xs return $ pre <> [t] <> p:ost ) <> r Accumulation will reverse lists. Where reversal is not allowed, a parameter xs :: [a] is replaced by the function (xs <>) :: [a] -> [a] . In one place, reversal is kept (because it is irrelevant), and that's why it appears in the above - and contributes to the exotic order of output. Truly a work of art. - I still wonder * can we document this (perhaps find the original documentation)? * was this necessary (or can the compiler do these transformations)? - J.

(sorry, I will be quiet after this) For historical references, see https://www.imn.htwk-leipzig.de/~waldmann/etc/data-list-permutations/ The code appeared in the Haskell 1.3 Library report (1996) and was modified in 2007. - J.
participants (1)
-
Johannes Waldmann