Dropin' Science
Dropin' Science

Reputation: 89

SML list option recusion; how to use recursion to output a SOME list

Currently, my code takes in a string s and a string list sl and returns a string list where s was removed (once)

fun all_except_option (s, sl) =
    case sl of
    [] => []
      | hd::tl = if same_string(s, hd)
          then tl
          else hd::all_except_option(s, tl) 

However, what I want is to return NONE if the string s is not in the list and if it is, return SOME (output of the current function). However, I can't simply add SOME( before hd::all_except_option(s, tl) since hd will be appended to something that outputs an option and I can't figure how to do it.

Edit: thanks everyone!

Upvotes: 1

Views: 518

Answers (5)

Omar Shawky
Omar Shawky

Reputation: 19

In case you are struggling too much like me and took too much to solve that question from the course, here is a solution for you that you can simply understand:

(* string * string list -> string list option *)
(* Eliminate a specific string from a list of string*)
(* fun all_except_option (s, los) = [] *) (* stub *)
fun all_except_option (exc, los) =
  let
    fun all_except_option_acc (los, acc, f) = 
      case los of
        [] => 
          if f then SOME acc
          else NONE
      | s::los' =>  
          if same_string (s, exc) then 
            all_except_option_acc(los', acc, true)
          else 
            all_except_option_acc(los', s::acc, f)
  in
    all_except_option_acc(los, [], false)
  end

Upvotes: 0

sshine
sshine

Reputation: 16105

Andreas Rossberg provided two complete examples.

Here is a variation where the pattern matching is in the argument of the function instead:

fun curry f x y = f (x, y)

fun all_except_option (s, []) = NONE
  | all_except_option (s, t::ts) =
      if s = t
      then SOME ts
      else Option.map (curry op:: t) (all_except_option (s, ts))

Where curry op:: t is the function that takes a list and puts t in front of it:

- curry op:: "x" ["y", "z"];
> val it = ["x", "y", "z"] : string list

and is equivalent to fn ss' => t::ss'.

Upvotes: 0

Andreas Rossberg
Andreas Rossberg

Reputation: 36088

fun all_except_option (s, ss) =
    case ss of
      [] => NONE
    | s'::ss' =>
        if s = s' then SOME ss' else
        case all_except_option (s, ss') of
          NONE => NONE
        | SOME ss'' => SOME (s'::ss')

Note that this only removes the first occurrence of s, which mirrors your version.

You can also use Option.map to avoid the nested case:

fun all_except_option (s, ss) =
    case ss of
      [] => NONE
    | s'::ss' =>
        if s = s' then SOME ss'
        else Option.map (fn ss' => s'::ss') (all_except_option (s, ss'))

Upvotes: 1

ruakh
ruakh

Reputation: 183211

You can use

case all_except_option(s, tl) of ...

to match the two different cases and handle each in the appropriate way.

Upvotes: 0

Scott Hunter
Scott Hunter

Reputation: 49803

It sounds like you need a new function:

fun some_option(s,sl) = SOME( all_except_option(s, sl) )

Well, not quite that, as it doesn't handle the case where all_except_option returns [], but I'll leave that as an exercise.

Upvotes: 1

Related Questions