OCaml Validation module

Hey @enetsee,

I’m trying to add a new semantic check and can’t figure out how to turn a list of Validate.ok | Validate.error’s into a single Validate error. I have the following code:

      match function_block_stmts_opt with
      | Some [] | None -> ok ()
      | Some ls ->
        List.map ~f:check_fun_def_body_in_block ls |> sequence

where check_fun_def_body_in_block returns a Validate.ok or error as well. I’m getting this type error:

Error: This expression has type unit list t
       but an expression was expected of type unit t
       Type unit list is not compatible with type unit 

on the map and sequence call. I seem to remember you explicitly saying using the Validation applicative (not monad!) helps you deal with this case, but I can’t figure out how to use it. Help appreciated!

Hey,

The type of sequence is 'a t list -> 'a list t (where t is Validation.Make(Semantic_error).t).

You are applying check_fun_def_body_in_block : ('a,'b) stmt list option -> unit t to each element of the list giving you a unit t list. When you then sequence the effects, you get back unit list t.

However, in the first case of your match statement, you are returning unit t. Since unit t does not equal unit list t (!) it will not type check.

There are two ways to fix this:

  • return ok [] from the first branch and add Validation.map ~f:List.concat after sequence on the second branch;
  • add Validation.map ~f:(fun _ -> ()) after sequence on the second branch.

(EDIT: it turns out I can’t code without a type checker… you will still have to flatten the list of lists for the first option, above)

The semantic check code isn’t quite where I want it to be at the moment so it probably doesn’t matter which you use (Semantic_check currently performs type checking which requires a monadic interface - see below) but I would usually prefer the first option. It might be worth taking a look at the docs I added explaining apply works here.

If the computations are independent (i.e. checking the validity of one statement does not depend on the result of a previously checked statement) you only require the Applicative interface. Validation should not really support the Monad interface since the implementation violates the monad laws and, more practically, doing so means it doesn’t actually accumulate errors through monadic bind!.

NB In the PR I submitted yesterday for semantic warnings I actually changed the interface to validation to match the standard Core_kernel signatures so sequence is called all there.

1 Like