smlmlmosml

SML Unbound value identifier Error in Insert Function


Im having an issue with my separate function. Separate returns a list that inserts element x after each k elements of list l (counting from the end of the list). For example, separate (1, 0, [1,2,3,4]) should return [1,0,2,0,3,0,4] and separate (3, 0, [1,2,3,4]) should return [1,0,2,3,4]. Whenever I run any tests on it i get the error:

! Unbound value identifier: separate 

This is the code i'm using:

 (*Function returns length of lst   *)
fun length(lst: int list): int =
  case lst of
    [] => 0
  | h::t => 1 + length(t) 

(*Insert element x at the kth position in the list 
  and return the new list*)
fun kinsert [] x k = [x]
  | kinsert ls x 0 = x::ls
  | kinsert (l::ls) x k = l::(kinsert ls x (k - 1)) 

(* c: keeps track of where we are in the list 
   n: determines if we insert element at given position  
   z: holds length of the list *)
fun sep_help k x l c n z= 
  if c = z then l 
  else if n = k then (sep_help k x (kinsert l x c) (c+2) 0 z )
  else (sep_help k x l (c+2) (n+1) z) ; 

(*Returns list l with x inserted after each k element *)
fun separate (k: int, x: 'a, l: 'a list) : 'a list = 
  | separate k x l = (sep_help k x l 0 0 (length l));  

Anyone know what might be causing the error?


Solution

  • Your separate looks like its a merge of two different definitions - first an uncurried version that has no definition, and then a curried version that has one.

    You probably meant

    fun separate (k: int, x: 'a, l: 'a list) : 'a list = sep_help k x l 0 0 (length l);  
    

    But working backwards through a list complicates things quite a bit.
    It's much easier to work from the head towards the tail, and reverse the list before and after processing.
    Then "all" you need is a helper that inserts an element in every k:th place in a list.
    Something like this, perhaps:

    (*Returns list l with x inserted after each k element *)
    fun separate (k: int, x: 'a, l: 'a list) : 'a list = 
      let
        fun kinsert [] _ = []
          | kinsert ls 0 = x::(kinsert ls k)
          | kinsert (l::ls) i = l::(kinsert ls (i-1))
    in
        List.rev (kinsert (List.rev l) k)
    end