# Constraining type parameter to be polymorphic variant

**URL:** <https://discuss.ocaml.org/t/constraining-type-parameter-to-be-polymorphic-variant/7159>\
**Category:** Learning\
**Tags:** polymorphism\
**Created:** [January 25, 2021, 12:41pm UTC](https://discuss.ocaml.org/t/constraining-type-parameter-to-be-polymorphic-variant/7159 "2021-01-25T12:41:46Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![dgllghr](https://avatars.discourse-cdn.com/v4/letter/d/41988e/32.png) [@dgllghr](https://discuss.ocaml.org/u/dgllghr)\
**Post date:** [January 25, 2021, 12:41pm UTC](https://discuss.ocaml.org/t/constraining-type-parameter-to-be-polymorphic-variant/7159/1 "2021-01-25T12:41:46Z")

</div>

I am writing a function that stores a key value pair asynchronously. The key is a string but the value is supplied as an async stream so that it can be streamed to the key-value store without loading the whole value into memory. I am making use of `lwt` for async and the `result` type to represent success/failure.

What I am struggling with is how to combine the error type of the input value stream with the error type that represents an error writing to the key-value store. I think this problem can be represented without the async twist, but I wanted to leave it in to show that the value cannot be resolved before calling this function.

Currently, what I have looks something like this:

```auto
val store:
  t -> (* client *)
  string -> (* key *)
  Bigstringaf.t Lwt_stream.t -> (* value to store. contents are streamed in asynchronously *)
  (unit, 'error) Lwt_result.t -> (* promise that indicates whether contents stream succeeded or failed *)
  (unit, [`Contents_error of 'error | ClientError.t]) Lwt_result.t (* ClientError.t is a polymorphic variant type *)

```

I was hoping to able to constrain the `'error` type parameter to be a polymorphic variant so that I could do this:

```auto
val store:
  t -> (* client *)
  string -> (* key *)
  Bigstringaf.t Lwt_stream.t -> (* value to store. contents are streamed in asynchronously *)
  (unit, 'error) Lwt_result.t -> (* promise that indicates whether contents stream succeeded or failed *)
  (unit, [> 'error | ClientError.t]) Lwt_result.t (* NOTE the `Contents_error variant is no longer needed *)

```

Is there a way to add the polymorphic variant constraint? If not, is there a better approach to combining variants?

If possible, I would like to avoid the “big ball of mud” error approach (often found in Rust) where every error that can occur in the program/library is added to one giant error variant. I don’t like this approach because it makes it hard to know which errors actually need to be handled after calling a function, which is, IMHO, the biggest advantage of the `result` type to begin with! But I am open to being convinced otherwise.

---

<div class="post-metadata">

**Author:** ![yawaramin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/yawaramin/32/3384_2.png) [@yawaramin](https://discuss.ocaml.org/u/yawaramin)\
**Post date:** [January 25, 2021, 2:44pm UTC](https://discuss.ocaml.org/t/constraining-type-parameter-to-be-polymorphic-variant/7159/2 "2021-01-25T14:44:15Z")

</div>

You mean like this: [prometo/Yawaramin\_\_Prometo.rei at ef7229d3cbfe9980e32feef8e882785b49a96434 · yawaramin/prometo · GitHub](https://github.com/yawaramin/prometo/blob/ef7229d3cbfe9980e32feef8e882785b49a96434/src/Yawaramin__Prometo.rei#L15) (ReasonML syntax but you should be able to convert it to OCaml)

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [January 25, 2021, 3:33pm UTC](https://discuss.ocaml.org/t/constraining-type-parameter-to-be-polymorphic-variant/7159/3 "2021-01-25T15:33:28Z")

</div>

The notation

```ocaml
val f: [< t] -> unit

```

only works with type declaration, not type expressions. Constraining the type variable `'error` to the polymorphic variant kind is thus not going to work. (In general, polymorphic variants do not implement set operations at the type-level).

However, in your case, you can rewrite your type as

```ocaml
val store : t -> string -> Bigstringaf.t Lwt_stream.t -> 
  (unit, 'error ) Lwt_result.t -> 
  (unit, [> ClientError.t] as 'error ) Lwt_result.t 

```

The interesting part is that the `'error` type variable is shared between the input and the output, thus all errors in the input can appears in the output. Moreover, the output is constrained to positively contain a `ClientError.t` .

Note however that in order to use this function, you might need to use explicit coercion.  
For instance, in this simplified example:

```ocaml
let with_random_error x =
  if Random.float 1. > 0. then `Random_failure else x
let ok = with_random_error `Ok
let known_error () : [`Known_failure] = `Known_failure
let error = with_random (known_error ())

```

fails with

> Error: This expression has type [`Known_failure] but an expression was expected of type [> `Random\_failure]  
> The first variant type does not allow tag(s) `Random\_failure

because the typechecker cannot add ``Random_failure` to the closed set of failures of `known_failure`. The solution here is an explicit cast:

```auto
let ok_too =
  with_random_error (known_error () :> [`Random_failure | `Known_failure])

```

---

<div class="post-metadata">

**Author:** ![dgllghr](https://avatars.discourse-cdn.com/v4/letter/d/41988e/32.png) [@dgllghr](https://discuss.ocaml.org/u/dgllghr)\
**Post date:** [January 25, 2021, 4:13pm UTC](https://discuss.ocaml.org/t/constraining-type-parameter-to-be-polymorphic-variant/7159/4 "2021-01-25T16:13:38Z")

</div>

Very cool! That did the trick. The fact that variant types don’t implement set operations is good to know and means I need to think about them differently.

I don’t mind adding a type coercion internal to the library, especially if it is the tradeoff necessary for error clarity. I’ll have to think about how to structure things so the coercion is not necessary at the API boundary, though.
