How to clean a list for a specific string and return the cleaned list or NONE


I need to write a function to answer these specifications:

clean_list( [],s1] = NONE

clean_list( xs, "") = NONE

clean_list ([s1, s1, s1, s1], s1) = NONE

clean_list([s1, s2, s3, s2, s1], s3) = [s1, s2, s2, s1]

where s1, s2, s3 are some strings and xs a list of strings.

I was able to do it using the two helper functions is_into(xs: string list, s1: string) -> bool and remove(xs: string list, s1: string) -> string list but it seems ugly to recurse twice through the list.

clean_list(xs: string list, s1: string) =
    case (xs, s1) of
         ( [], _ ) => NONE
        |( _, "" ) => NONE
        |( _, _) => if is_into(xs, s1)
                    then remove(xs, s1)
                    else NONE

Is there a way to do it without recursing in the list twice (once in is_into and once in remove)?

Note: None of builtin functions are to be used.

Sorry i forgot an important case in the specifications

clean_list ([s1, s2, s3, s4], s10] = NONE

You can easily go through the list once, element by element and removing all that matches the given string, returning SOME lst at the end, where lst is the resulting list

fun clean_list ([], _ ) = NONE
  | clean_list (_, "") = NONE
  | clean_list (xs, str) =
      fun clean_list' [] = []
        | clean_list' (x::xs) =
          if x = str then
            clean_list' xs
            x :: clean_list' xs
      SOME (clean_list' xs)


I noticed that the above code actually doesn't handle the case: clean_list ([s1, s1, s1, s1], s1) = NONE. However this is an easy fix.

I can see that given your new updated specification, that if the element is not in the list in the first place, then NONE should be returned. This is the same as saying, if no elements was removed while going through all the elements, then return NONE.

Hopefully you can see that this can be implemented by added an extra Boolean argument to the helper function, initially setting it to false, and then passing along its value in each recursive call, except in the case where an element is removed, here it can always be set to true.

This can then be used to determine weather to return the SOME lst, where lst is the resulting list, or NONE if no elements was removed.

Given these two things, that needs to be fixed, it would probably bee a good idea to have the helper function built up its result in an accumulating argument, instead. This way you have full control and can easily return NONE when the accumulating list is empty at the end.