我正在写我的第一个ppx扩展名。这个想法是支持多态print
函数,类似于Haskell中的show
。
(我知道存在其他更强大的解决方案,但我希望了解更多有关其工作原理的方法。)
我采用的方法与描述的方法here非常相似:我有一个查找%[print <expr>]
标记的映射器,然后用{{1}的字符串表示替换它们}。例如,
<expr>
这适用于常量表达式,但我想支持任意表达式代替[%print 1] ==> string_of_int 1
[%print "aksljd"] ==> "aksljd"
。它应该用最终类型的打印机包装它们。
我目前的做法是使用<expr>
将Typecore.type_expression
转换为Parsetree.expression
,然后匹配Typedtree.expression
的{{1}}字段并确定用...替换整个表达式。例如,对于类型exp_type
,我会将Typedtree.expression
替换为type test = A of int | B of string
,[%print A 1]
必须按惯例存在。)
这不起作用,因为show_test (A 1)
将类型环境作为参数,而我无法获得当前类型的环境&#39;在重写时,因为类型检查甚至还没有执行,然后...... show_test
导致Typecore.type_expression
导致[%print 1 + 1]
,应该这样做。
有没有人有解决方案?如果我完全朝着错误的方向前进,请随意指出这一点。 :P
答案 0 :(得分:3)
评论中的讨论摘要:Haskell中的show
并不像这样(并且不能)。 Haskell中的Show a =>
将被转换为OCaml中的显式模块参数。该模块的值为print : a -> string
。 Haskell通过查找您(或库)已声明的Show
的{{1}}实例来推断此模块参数,但在OCaml中,您必须手动传递该模块。在Haskell中声明a
实例类似于在OCaml中实例化一个仿函数。
在Haskell和OCaml中,在问题中预处理表达式在以下情况下具有可疑含义:
Show
如果let f x = [%print x]
(即没有Haskell类型类实例可用且没有传递OCaml模块)。
为了使其更加完整,许多其他分析类型的ppx重写器从类型定义或声明生成代码,而不是从表达式生成代码。
答案 1 :(得分:2)
ppx基本上不支持你想要做的事情。正如您所指出的,ppx在解析之后,尚未完成类型检查。 由于编译器的当前架构,很难键入检查任意表达式。
如果您想要破解,可以阅读this。 :) 作者将在2周的ocaml研讨会上做一个关于它的演示,应该有一个视频。