2

Rewrite ppx based on the base type

 2 years ago
source link: https://www.codesd.com/item/rewrite-ppx-based-on-the-base-type.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Rewrite ppx based on the base type

advertisements

I'm writing my first ppx extension. The idea is to support a polymorphic print function, similar to show in Haskell.

(I'm aware that other more robust solutions exist, but I wish to learn more about how this works.)

The approach I've taken is very similar to the method described here: I have a mapper which looks for %[print <expr>] tags, then replaces them with a string representation of <expr>. For example,

[%print 1] ==> string_of_int 1
[%print "aksljd"] ==> "aksljd"

This works fine for constant expressions, but I want to support any arbitrary expression in place of <expr>. It should just wrap them with a printer of the final type.

My current approach is to use Typecore.type_expression to turn a Parsetree.expression into a Typedtree.expression, then match on the exp_type field of the Typedtree.expression and determine what to replace the whole expression with. For example, for a type type test = A of int | B of string, I would replace [%print A 1] with show_test (A 1) there (show_test must be present by convention).

This doesn't work because Typecore.type_expression takes a type environment as an argument, and I can't get the 'current type environment' at the point of rewriting, because type-checking hasn't even been performed then... [%print 1 + 1] with Typecore.type_expression Env.empty causes Unbound value +, as it should.

Does anyone have a solution to this? If I'm heading in the wrong direction entirely, feel free to point this out. :p


A summary of the discussion in comments: show in Haskell doesn't work like this (and can't). Show a => in Haskell would be translated to an explicit module argument in OCaml. That module would have a value with signature like print : a -> string. Haskell infers this module argument by finding an instance of Show for a that you (or libraries) have declared, but in OCaml you would have to pass the module manually. Declaring the Show instance in Haskell is analogous to instantiating a functor in OCaml.

In both Haskell and OCaml, preprocessing expressions as in the question would have dubious meaning in cases such as:

let f x = [%print x]

If f : 'a -> string (i.e. no Haskell type class instance is available and no OCaml module is being passed).

To make it more complete, many other ppx rewriters that analyze types generate code from type definitions or declarations, not from expressions.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK