Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive discriminated union case types

How can I create OCaml/F# DU type where its cases are subsets of other cases?

For example, I want to make a symbol table which contains different symbol declaration types, such as program types, variables and functions.

At first glance, I can see that a variable contains its type, function also contains a type and many parameter variables. So I'd like to use 1 DU, instead of seperating to many records or aliases:

type Symbol =
    | TypeSymbol of id:string
    | VariableSymbol of id:string * type':TypeSymbol
    | FunctionSymbol of id:string * params':VariableSymbol list * type':TypeSymbol

But this is wrong, because the DU cases cannot be subsets of other cases. How can I reformat types to declare that DU cases are recursive to each other?

like image 818
MiP Avatar asked Jun 21 '17 04:06

MiP


1 Answers

For F#, the simplest solution would be to create smaller single-case DUs and reference those:

type T = T of id:string
type V = V of id:string * type':T
type Symbol =
   | TypeSymbol of T
   | VariableSymbol of V
   | FunctionSymbol of id:string * params': V list * type':T

Its usage through decomposition could be something like this.

let rec print x = 
   match x with
   | TypeSymbol (T typeId) -> 
      typeId

   | VariableSymbol (V (varId, T typeId)) -> 
      sprintf "%s : %s" varId typeId

   | FunctionSymbol (funId, params', T typeId) ->         
      let printedParams = 
         params'
         |> List.map (VariableSymbol >> print) 
         |> String.concat ") -> ("
      sprintf "%s = (%s) -> %s" funId printedParams typeId
like image 101
piaste Avatar answered Sep 28 '22 02:09

piaste