0
fun p(L) =
    [L] @ p( tl(L) @ [hd(L)] );

If L is [1,2,3] then I want to have a [ [1,2,3], [2,3,1], [3,1,2] ].

Since every time I append the first num to the end, then if L = [] then [] doesn't work here.

How to stop the function once it has the three lists?

Jam
  • 113
  • 2
  • 7

2 Answers2

2

You can have a parameter x in the function to keep track of how many levels deep in the recursion you are.

fun p(L, x) =
  if x < length(L) then [L] @ p(tl(L) @ [hd(L)], x+1)
  else [];

Then call the function with x=0.

p([1, 2, 3], 0)

And if you don't like the extra parameter, then as you probably know you can define another function and make it equal to the p function with the parameter forced to 0.

fun p0(L) = p(L, 0);

p0([1, 2, 3]); (* same result as p([1, 2, 3], 0); *)
Randy Hickey
  • 193
  • 4
1

Let me show some more implementation variants. First of all, let's define an auxiliary function, which rotates a list 1 position to the left:

(* operates on non-empty lists only *)
fun rot1_left (h :: tl) = tl @ [h]

Then the p function could be defined as follows:

fun p xs =
  let
    (* returns reversed result *)
    fun loop [] _ _   = []
      | loop xs n res = 
          if n = 0
          then res
          else loop (rot1_left xs) (n-1) (xs :: res)
  in
      List.rev (loop xs (length xs) [])
  end

It's usually better (performance-wise) to add new elements at the beginning of the list and then reverse the resulting list once, than to append to the end many times. Note: this version does one spurious rotate at the end and I could have optimized it out, but didn't, to make code more clear.

We have calculated the length of the given list to make its rotated "copies", but we don't have to traverse xs beforehand, we can do it as we rotate it. So, we can use xs as a kind of counter, recursively calling the loop helper function on the tail of the xs list.

fun p xs =
  let
    (* returns reversed result *)
    fun loop [] _       _   = []
      | loop xs []      res = res
      | loop xs (_::tl) res = 
          loop (rot1_left xs) tl (xs :: res)
  in
      List.rev (loop xs xs [])
  end

Having done that, we are now closer to implementing p as a foldl function:

fun p xs =
  (List.rev o #1)
      (List.foldl
         (fn (_, (res, rot)) => (rot::res, rot1_left rot))
         ([], xs)
         xs)

The second argument to the List.foldl function is our "accumulator", which is represented here as a pair of the current (partial) result as in the previous implementations and the current rotated list. That explains (List.rev o #1) part: we need to take the first component of the accumulator and reverse it. And as for the ([], xs) part -- the current result is empty at the beginning (hence []) and we start rotating the initial xs list. Also, the _ in (_, (res, rot)) means the current element of the given xs, which we don't care about, since it just serves as a counter (see the prev. variant).

Note: o stands for function composition in Standard ML.

Anton Trunov
  • 15,074
  • 2
  • 23
  • 43