1

I wrote the following function in SML:

fun find_value [] item = ~1.0
  | find_value ((x:string,y:real)::xt) item = 
    if item = x then y
    else find_value xt item;

This function gets a list string * real and a string and returns the value of the element with the same string. For example:

- find_value [("goo",4.0),("boo",5.0)] "goo";
val it = 4.0 : real`. 

The problem is with my implementation, it will return ~1.0 if it didn't find an element with xstring in it. so if for example I have an element with value ~1.0 it will return it and I won't know if the list is empty or if the element isn't in the list or there was an element with the same string and value of ~1.0.

Example:

find_value [("goo",~1.0),("boo",5.0)] "goo";
find_value [] "goo";

both will return val it = ~1.0. Is there any other idea for implementation?

sshine
  • 15,635
  • 1
  • 41
  • 66
TTaJTa4
  • 810
  • 1
  • 8
  • 22

1 Answers1

0

What an excellent question. This is what the 'a option type (documentation, Q&A) is for.

Your find_value could instead look like:

fun find_value [] _ = NONE
  | find_value ((key,value)::pairs) key1 =
      if key = key1
      then SOME value
      else find_value pairs key1

Now your two examples will instead be:

- find_value [("goo",~1.0),("boo",5.0)] "goo";
val it = SOME ~1 : real option
- find_value [] "goo";
val it = NONE : 'a option

Now callers of find_value must check if the value exists, e.g. with:

case find_value "foo" of
     NONE       => ... do some error handling ...
   | SOME value => ... proceed ...

A less safe alternative is exceptions:

exception NotFound of string
fun find_value [] key1 = raise NotFound key1
  | find_value ((key,value)::pairs) key1 =
      if key = key1
      then value
      else find_value pairs key1

The advantage here appears to be that you don't have to unpack the result, depending on whether or not it's found, and if you don't know how to properly handle that a value was not found, you can simply defer from catching the exception until the right point in the call-stack.

But the drawback is that you have to remember to catch the exception and that you can't be certain that code that calls other code will be exception-free, since any function that raises an exception will "taint" its callers.

Generally, having exceptions in your code is good to avoid as you're learning how to use a strongly typed programming language, because then the compiler and you can better reason about possible scenarios when running the program.

sshine
  • 15,635
  • 1
  • 41
  • 66