• bahmanm@lemmy.ml
    link
    fedilink
    English
    arrow-up
    1
    ·
    10 months ago

    I’m no OCaml expert and mostly I’m casually browsing.

    The arguments presented read quite compelling. What are your thoughts? Does the conclusion make sense? Have you had any real world experience w/ GADTs that you could share?

    • Chimrod@lemmy.world
      link
      fedilink
      English
      arrow-up
      2
      ·
      10 months ago

      I’ve tried something recently in a project with Dream.

      Suppose you have an url like /page/param1/param2/ : you want to be able to do three things:

      1. Build this url in the application in a safe way, which mean : param1 -> param2 -> string
      2. Create a route which handle this url pattern (the compilation should fail if you don’t handle all the arguments)
      3. Ensure the handler will have the signature param1 -> param2 -> Dream.handler

      Of course, some pages will have two arguments, some other three, and you have to find a way represent this in the type system.

      For this, I’ve used a gadt:

      
      type ('a, 'b) t =
        | Static : string * ('a, 'b) t -> (unit -> 'a, 'b) t
        | Int : string * ('a, 'b) t -> (int64 -> 'a, 'b) t
        | String : string * ('a, 'b) t -> (string -> 'a, 'b) t
        | End : ('a, 'a) t
      

      The string is the parameter name in the url (id, login, …) and the gadt make the representation for this parameter in the type system. This gives me a way to declare some urls in the application:

      val root : (unit -> 'a, 'a) t
      (** The path to root / *)
      
      val topic_url : (string -> 'a, 'a) t
      (** The path to /:topic *)
      
      val thread_url : (string -> int64 -> 'a, 'a) t
      (** The path to /:topic/:thread *)
      

      Then I have some some functions wihch handle this gadt:

      val repr : (unit -> ('a, 'b) t) -> string
      (** Represent the route associated with this path *)
      
      val unzip : (unit -> ('a, 'b) t) -> (string -> string) -> 'a -> 'b
      (** Extract the parameters from the request. 
      
          [unzip path extract f] will apply the function extract for all the
          arguments in the path, and gives them to f 
      
          The function [extract] is given in argument in order to break dependency
          circle.
      
          This should be something like: 
      
              let extract_param request name =
                Dream.param request name |> Dream.from_percent_encoded
      
      *)
      
      • bahmanm@lemmy.ml
        link
        fedilink
        English
        arrow-up
        1
        ·
        10 months ago

        Thanks for your reply. I’m still not sure if I have managed to wrap my head around this 😕 I guess I need to re-read the relevant chapter from RWO book. I’ll post back here I’m finally able to understand handler in your case.