# Help writing a minimal macro

**URL:** <https://discuss.ocaml.org/t/help-writing-a-minimal-macro/11463>\
**Category:** Learning\
**Created:** [February 20, 2023, 6:39am UTC](https://discuss.ocaml.org/t/help-writing-a-minimal-macro/11463 "2023-02-20T06:39:29Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![zeroexcuses](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeroexcuses/32/1692_2.png) [@zeroexcuses](https://discuss.ocaml.org/u/zeroexcuses)\
**Post date:** [February 20, 2023, 6:39am UTC](https://discuss.ocaml.org/t/help-writing-a-minimal-macro/11463/1 "2023-02-20T06:39:29Z")

</div>

Consider the following code. I define a type once, then I repeat myself 3 times

- create table
- first part of insert values
- second part of insert values

This then happens for EVERY struct/table I define. This is quite error prone, as I’m looking at tens of structs/tables.

In theory, I believe ppx can help me reduce this type of repetition. However, I’m new to ppx. Can someone help with a minimal sample macro? I’m mainly looking for a minimal “skeleton” I can then hack on.

```auto
module Row __Browser__ Self_Event = struct
  type t = {
    self_id: Fixed_String_16.t;
    self_count: int;
    self_time: Time_Milli.t;

    tag_0: Fixed_String_16.t;
    tag_1: Fixed_String_16.t;
    tag_2: Fixed_String_16.t;

    data: string;
  };;

  let drop_tbl = {sql| DROP TABLE IF EXISTS main_logs.browser_self |sql};;

  let create_tbl = {sql|
  CREATE TABLE IF NOT EXISTS main_logs.browser_self
  (
      self_id FixedString(16),
      self_count UInt32,
      self_time_ymd UInt32,
      self_time_hmsm UInt32,

      tag_0 FixedString(16),
      tag_1 FixedString(16),
      tag_2 FixedString(16),

      data String,
  ) ENGINE = MergeTree()
  ORDER BY ()
  |sql};;

  let insert_into = {sql|
  INSERT INTO main_logs.browser_self ( self_id, self_count, self_time_ymd, self_time_hmsm, tag_0, tag_1, tag_2, data) VALUES
  |sql};;

  let insert_values (v: t) (module Q: Single_Quote_Util) = String.concat " " [ 
    "(";
    Q.quote_string v.self_id.raw;
    Q.quote_int v.self_count;
    Q.quote_int v.self_time.year_month_day;
    Q.quote_int v.self_time.hour_minute_second_milli;

    Q.quote_string v.tag_0.raw;
    Q.quote_string v.tag_1.raw;
    Q.quote_string v.tag_2.raw;

    Q.quote_string v.data;
    ")"
  ];;

end

```

---

<div class="post-metadata">

**Author:** ![zeroexcuses](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeroexcuses/32/1692_2.png) [@zeroexcuses](https://discuss.ocaml.org/u/zeroexcuses)\
**Post date:** [February 20, 2023, 6:42am UTC](https://discuss.ocaml.org/t/help-writing-a-minimal-macro/11463/2 "2023-02-20T06:42:35Z")

</div>

EDIT: Better minimal example:

```auto
module Row __Browser__ Min = struct
  type t = {
    self_count: int;
    data: string;
  };;

  let drop_tbl = {sql| DROP TABLE IF EXISTS main_logs.browser_self |sql};;

  let create_tbl = {sql|
  CREATE TABLE IF NOT EXISTS main_logs.browser_self
  (
      self_count UInt32,
      data String,
  ) ENGINE = MergeTree()
  ORDER BY ()
  |sql};;

  let insert_into = {sql|
  INSERT INTO main_logs.browser_self ( self_count, data) VALUES
  |sql};;

  let insert_values (v: t) (module Q: Single_Quote_Util) = String.concat " " [ 
    "(";
    Q.quote_int v.self_count;
    Q.quote_string v.data;
    ")"
  ];;
end

```

I think this strips out all non-primitive types, yet still captures the “core” of the problem that there is one definition + 3 repetitions, and the 3 repetitions can be replaced via a macro.

---

<div class="post-metadata">

**Author:** ![zeroexcuses](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeroexcuses/32/1692_2.png) [@zeroexcuses](https://discuss.ocaml.org/u/zeroexcuses)\
**Post date:** [February 20, 2023, 6:59am UTC](https://discuss.ocaml.org/t/help-writing-a-minimal-macro/11463/3 "2023-02-20T06:59:41Z")

</div>

Is there a readable impl of `@@deriving fields` from [Records - Real World OCaml](https://dev.realworldocaml.org/records.html#first-class-fields) ? Understanding that macro should suffice for everything I need.

---

<div class="post-metadata">

**Author:** ![panglesd](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/panglesd/32/3931_2.png) [@panglesd](https://discuss.ocaml.org/u/panglesd)\
**Post date:** [February 20, 2023, 9:29am UTC](https://discuss.ocaml.org/t/help-writing-a-minimal-macro/11463/4 "2023-02-20T09:29:23Z")

</div>

The ppxlib repo has two examples, one of which is a deriver, which derives accessor functions from a record type: [ppxlib/examples/simple-deriver at main · ocaml-ppx/ppxlib · GitHub](https://github.com/ocaml-ppx/ppxlib/tree/main/examples/simple-deriver)

If you are new to PPX, you might be interested in [Preprocessors and PPXs · OCaml Tutorials](https://ocaml.org/docs/metaprogramming) (for some general introduction to PPXs) and [Documentation · ppxlib 0.29.1 · OCaml Packages](https://ocaml.org/p/ppxlib/0.29.1/doc/index.html) (for some material about writing PPXs).

---

<div class="post-metadata">

**Author:** ![zeroexcuses](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeroexcuses/32/1692_2.png) [@zeroexcuses](https://discuss.ocaml.org/u/zeroexcuses)\
**Post date:** [February 21, 2023, 12:45am UTC](https://discuss.ocaml.org/t/help-writing-a-minimal-macro/11463/5 "2023-02-21T00:45:16Z")

</div>

@panglesd : Thanks for the instructive example. I typed up the code, and after fixing many typos I introduced, the code compiled.

For debugging purposes, how do I “printf” the output of the macro?

I.e. I want the output after macro expansion, but before it starts rewriting into whatever IR it uses.

I’m using dune for all my projects.

Thanks!

---

<div class="post-metadata">

**Author:** ![mooreryan](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/mooreryan/32/2843_2.png) [@mooreryan](https://discuss.ocaml.org/u/mooreryan)\
**Post date:** [February 21, 2023, 12:59am UTC](https://discuss.ocaml.org/t/help-writing-a-minimal-macro/11463/6 "2023-02-21T00:59:09Z")

</div>

If you mean you want to see the code that the ppx generates (ie after expansion), you can use

```auto
$ ocamlc -stop-after parsing -dsource <file.pp.ml> > blah.generated.ml

```

That `file.pp.ml` will be in the `_build` dir.

Edit: [this](https://tarides.com/blog/2019-05-09-an-introduction-to-ocaml-ppx-ecosystem) article from Tarides is a nice ppx intro if you’re looking for more reading materials.

---

<div class="post-metadata">

**Author:** ![zeroexcuses](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeroexcuses/32/1692_2.png) [@zeroexcuses](https://discuss.ocaml.org/u/zeroexcuses)\
**Post date:** [February 21, 2023, 3:18am UTC](https://discuss.ocaml.org/t/help-writing-a-minimal-macro/11463/8 "2023-02-21T03:18:27Z")

</div>

> [@panglesd](#):
>
> If you are new to PPX, you might be interested in [Preprocessors and PPXs · OCaml Tutorials](https://ocaml.org/docs/metaprogramming)

This is insane. I did not know you could specify SHELL SCRIPTS as “preprocessors” in dune. Truly fascinating.
