1

I'm trying to understand how to combine two anonymous functions in SML.

Consider:

val x = fn 5 => 5
        |  6 => 6;

val y = fn 3 => 3
        |  2 => 2;

I would like to create function z by combing x and y:

val z = fn 5 => 5
        |  6 => 6
        |  3 => 3
        |  2 => 2;

How can I achieve it?

vesii
  • 2,760
  • 4
  • 25
  • 71
  • 2
    You shouldn't normally write incomplete pattern matches like in x and y in the first place. That will generate a warning, which you best consider an error. The recommended way to express a partial function is to return an option. Once you do that, you can combine them easily by calling the first, and then the second if the first returned NONE. – Andreas Rossberg Jan 26 '19 at 09:03

1 Answers1

4

If you want to define a function which combines two functions in such a way that the second function is evaluated when the first function fails to provide a value for it, you would have to handle the Match exception which is raised when the first function fails:

val x = fn 5 => 5
        |  6 => 6;

val y = fn 3 => 3
        |  2 => 2;

val z = fn i => x i
    handle Match => y i;

This is somewhat ugly since arguably handle isn't really in the spirit of functional programming, but it does solve the problem. A cleaner solution would be to have z return an int option, but that would change the return type of your functions. The result could look like:

val x = fn 5 => SOME 5
        |  6 => SOME 6
        |  _ => NONE

val y = fn 3 => SOME 3
        |  2 => SOME 2
        |  _ => NONE

val z = fn i => case x i of
                  SOME j => SOME j
                | NONE => y i;

This result was the advantage of silencing all compiler warnings, but you would need to use pattern matching (the way z does) in any calling function to interpret the output. Note that pattern matching is able to extract the value. In this case, z just forwarded SOME j, but it could have used the integer value j directly if it needed to. See this question for more about options.

John Coleman
  • 51,337
  • 7
  • 54
  • 119
  • That what I had in mind. So `SML` does not provide any 'clean' way of solving it, without changing the type of `z`? – vesii Jan 26 '19 at 12:17
  • @vesii Changing the type of `z` so that it works without error trapping would also require changing the type of both `x` and `y` so that they return `int option` as well. It is by far the cleanest solution. – John Coleman Jan 26 '19 at 12:48
  • @vesii I added a bit to the answer to show how an option-based approach would look. – John Coleman Jan 26 '19 at 13:05
  • @vesii: You must, either way, provide some kind of result that communicates from the first function to the composition operator that there was no result. The clean way of doing this is via an error-aware return type, such as *'a option*, and the unclean solution is via exceptions. Those are the two kinds of ways you can express "null". To compose the lookups you can also encode your lookup table as values, e.g. via a lookup-based search tree. This can mutate at runtime. SML does not provide a macro-based solution for composing lookup functions at compile-time. – sshine Jan 28 '19 at 07:52