SML Types of rules don't agree and righthand side of clause doesn't agree with function result type

Viewed 83

I'm trying to write a function in sml that takes a function and applies it to all elements in a list. If any element returns NONE then the entire function evals to NONE but if any element returns SOME v then that element is added to the accumulator.

The final return value is SOME of the acculumator. Right now I'm getting two errors.

  1. hw4.sml:93.21-95.67 Error: types of rules don't agree [tycon mismatch] earlier rule(s): 'Z option -> 'Y option this rule: 'Z option -> 'X list in rule: SOME v => ((all_answers_helper ) xs') v @ acc
  2. hw4.sml:90.5-95.67 Error: right-hand-side of clause doesn't agree with function result type [tycon mismatch]
    expression: 'Z list -> 'Y list -> 'Y list option result type: 'Z list -> 'Y list -> 'Y list in declaration: all_answers_helper = (fn arg => (fn => ))
fun all_answers_helper f xs acc = 
        case xs of 
        [] => SOME acc
        | x::xs' => case f x of 
                    NONE => NONE
                    | SOME v => all_answers_helper f xs' v @ acc

But I have no idea what I'm doing wrong. All help is appreciated!

2 Answers

It looks like you're getting tripped up by operator precedence. Prefix function and constructor application ("normal ones", like SOME) bind tighter than infix application. So when you write all_answers_helper f xs' v @ acc that's the same as (all_answers_helper f xs' v) @ acc---the application of all_answers_helper binds tighter than that of @.

You can fix this by doing all_answers_helper f xs' (v @ acc) instead. Note that this would imply that v is itself a list. Based on your description of adding "the element" to the accumulator it is possible you instead mean all_answers_helper f xs' (v :: acc), i.e., to just cons the element on instead of appending two lists together.

I think @kopecs has it, but you may also find it useful to make use of pattern matching right in the function signature to make your code easier to reason about.

fun all_answers_helper _ [] acc = SOME acc
  | all_answers_helper f (x::xs) acc = 
      case f x of 
          NONE => NONE
        | SOME v => all_answers_helper f xs (v :: acc)

Understanding operator precedence is crucial to avoid programming errors, but you can also sidestep this by introducing local bindings.

fun all_answers_helper _ [] acc = SOME acc
  | all_answers_helper f (x::xs) acc = 
      case f x of 
          NONE => NONE
        | SOME v => 
             let 
               val updated_acc = v :: acc
             in
               all_answers_helper f xs updated_acc
             end
Related