# Generic subroutines

**URL:** <https://discuss.ocaml.org/t/generic-subroutines/13839>\
**Category:** Learning\
**Created:** [January 11, 2024, 7:50am UTC](https://discuss.ocaml.org/t/generic-subroutines/13839 "2024-01-11T07:50:14Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ban](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/ban/32/5017_2.png) [@Ban](https://discuss.ocaml.org/u/Ban)\
**Post date:** [January 11, 2024, 7:50am UTC](https://discuss.ocaml.org/t/generic-subroutines/13839/1 "2024-01-11T07:50:14Z")

</div>

I am trying to define generic subroutines but ocaml keeps instantiating them.  
Specifically, why does this code fail

```auto
let (example: (string * string) list -> (string * int) list -> string list)
  = fun l1 l2 ->
  let (local: (string * 'a) list -> string list) = fun l ->
    l |> List.map (fun (s,_) -> s) in
  [local l1; local l2] |> List.concat;;

let () =
  example [("a","b");("c","d")] [("e",6);("g",8);("i",0)]
  |> List.iter (
         fun str -> Printf.printf ">>> %s\n" str
       );;

File "./test.ml", line 5, characters 19-21:
5 | [local l1; local l2] |> List.concat
                       ^^
Error: This expression has type (string * int) list
       but an expression was expected of type (string * string) list
       Type int is not compatible with type string 

```

when this one succeeds?

```auto
let (local: (string * 'a) list -> string list) = fun l ->
  l |> List.map (fun (s,_) -> s);;
let (example: (string * string) list -> (string * int) list -> string list)
  = fun l1 l2 ->
  [local l1; local l2] |> List.concat;;

let () =
  example [("a","b");("c","d")] [("e",6);("g",8);("i",0)]
  |> List.iter (
         fun str -> Printf.printf ">>> %s\n" str
       );;

>>> a
>>> c
>>> e
>>> g
>>> i

```

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [January 11, 2024, 8:19am UTC](https://discuss.ocaml.org/t/generic-subroutines/13839/2 "2024-01-11T08:19:42Z")

</div>

> [@Ban](#):
>
> ` let (local: (string * 'a) list -> string list) = fun l ->`

The problem is the type annotation: here, the variable `'a` is an unification variable scoped to the body of `example`, not a “forall” variable, and it gets unified with both `string` and `int` in the body of `example`. In other words, by annotating `local` in this manner you actually keep it from being generalized. If you remove the type annotation the code should typecheck without issues.

If you **really** want to keep the type annotation, you need to write a “forall” type annotation:

```auto
let local: 'a. (string * 'a) list -> string list = fun l ->
  List.map (fun (s, _) -> s) l
in

```

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![K\_N](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/k_n/32/2793_2.png) [@K\_N](https://discuss.ocaml.org/u/K_N)\
**Post date:** [January 11, 2024, 8:33am UTC](https://discuss.ocaml.org/t/generic-subroutines/13839/3 "2024-01-11T08:33:24Z")

</div>

The relevant section in [the manual](https://v2.ocaml.org/releases/4.14/htmlman/types.html#sss:typexpr-variables). When you put a type annotation like this, it acts as a constraint, as @nojb explained. In that setting, the `'a` variable (that you write explicitly) is only generalized when you leave the top-level scope.  
So you can either:

- put an explicit polymorphic annotation `'a. ...`
- or not put any annotation
- or define `local` as a toplevel binding that gets generalized on its own
- or used an anonymous type variable `_` which does not suffer from the same restrictions:

```auto
let (example: (string * string) list -> (string * int) list -> string list)
    = fun l1 l2 ->
    let (local : (string * _) list -> string list) = fun l ->
      l |> List.map (fun (s,_) -> s) in
    [local l1; local l2] |> List.concat

```

As a final observation, should you be tempted to simplify the body of `local` as a partial application:  
`let local = List.map fst in`, the [value restriction](https://v2.ocaml.org/releases/4.14/htmlman/polymorphism.html#ss:valuerestriction) will kick in, preventing `local` from being generalized.

```auto
let (example: (string * string) list -> (string * int) list -> string list)
    = fun l1 l2 ->
    let (local : (string * _) list -> string list) = List.map fst in
    [local l1; local l2] |> List.concat;;
Error: This expression has type (string * int) list
       but an expression was expected of type (string * string) list
       Type int is not compatible with type string

```

---

<div class="post-metadata">

**Author:** ![Ban](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/ban/32/5017_2.png) [@Ban](https://discuss.ocaml.org/u/Ban)\
**Post date:** [January 11, 2024, 9:06am UTC](https://discuss.ocaml.org/t/generic-subroutines/13839/4 "2024-01-11T09:06:55Z")

</div>

Cool. Thanks folks. 🙂
