ocaml – I want to create a polymorphic open recursion

Question: Question:

When I was writing something like a solution to an expression problem using the Extensible variant types introduced in OCaml 4.02, I wanted a polymorphic open recursion, but I'm having trouble writing it.

module Lang = struct
  type 'a expr = ..
  type 'a expr +=
      Num : int -> int expr
    | App : ('a -> 'b) expr * 'a expr -> 'b expr

  type reval = { f : 'a. 'a expr -> 'a }

  (* open recursion. polymorphicなlet recだと拡張できないので。 *)
  (* evalをレコードにしてあるのは、Appのeval適用で型が異なる適用を二回行うので、forallを付ける必要があったから。 *)
  let open_eval (type a) (eval:reval) (exp:a expr) : a =
    match exp with
      Num i -> i
    | App (f, x) -> eval.f f (eval.f x)
    | _ -> failwith "no match"

(* Langのデータと関数の両方の拡張. *)
module Plus = struct
  type 'a Lang.expr += 
      Plus : (int -> int -> int) Lang.expr

  let open_eval (type a) (eval:Lang.reval) (expr:a Lang.expr) : a = 
    match expr with
      Plus -> (+)
    | x -> Lang.open_eval eval x

  let show : type a. a Lang.expr -> string = function
      Plus -> "plus"
    | Lang.App _ -> "app"
    | Lang.Num _ -> "num"
    | _ -> "no match"

Up to this point, it will compile. However, after that, I want to fix Plus.open_eval with the fixed point operator fix. How can I write the implementation of fix?
I know that the normal fixed point operator can be applied as in the article below.
I may not be able to write it in the first place, but I would appreciate your advice.

Postscript <br /> By the way,

let fix (`M x) y = y Lang.{ f = fun z -> x (`M x) y z }

Error: This field value has type'b Lang.expr->'b which is less general than'a.'a Lang.expr->'a
An error will occur when defining fix. orz

Answer: Answer:

First, let's take a fixed point without being particular about it.

open Lang

let rec fixed =
  fun x -> Plus.open_eval { f = fixed }  x

This is an error.

File "xxx", line 40, characters 36-41:
Error: This field value has type 'b Lang.expr -> 'b
       which is less general than 'a. 'a Lang.expr -> 'a

The reason is that in ML you can't take a polymorphic type inside a value defined by let , here fixed , let , and you can't plunge into a polymorphic field { f = .. } . It is in the same state as adding a question.

To give fixed a polymorphic type internally, you can explicitly specify the polymorphic type of fixed and use polymorphic recursion:

open Lang
open Plus

let rec fixed : 'a . 'a expr -> 'a = (* <= これがミソ *)
  fun x -> Plus.open_eval { f = fixed }  x  (* 内部でも fixed は多相型を持つので reval に突っ込める *)

let () =
  print_int @@ fixed
       (App (Plus, (App (App (Plus, Num 21), Num 21))),
        App (App (Plus, Num 21), Num 21)))

84 is output.

So-called fixed point operator

let rec fix f x = f (fix f) x

You have to open_eval to the value ('a eval -> 'a) -> 'a eval -> 'a to get into

let open_eval' = fun f x -> Plus.open_eval {f = f} x   (* うまくいかない… *)

I want a type like open_eval' : 'a. ('b . 'b expr -> 'b) -> 'a expr , but if this is written, the high rank polymorphic encoding by the polymorphic record feel is originally I don't need it, so I think it's impossible.

I think it's okay to give up fix if you realize the title of the question that you want to create a polymorphic open recursion …

Scroll to Top