OUnit framework有一个功能assert_equal
哪个可以(除其他外)进行论证 pp_diff
以更易读的方式格式化两个输入的差异。由于数据结构在现实世界的应用程序中变得相当大,这似乎非常有用。
然而,手动实现它似乎也很乏味(特别是在开发过程中,当数据结构可能经常改变时)。所以我想知道是否有任何方法(最好是基于ppx的)来生成这样的函数?
如果 OCaml 中(还)没有这样的东西,那么在通常的嫌疑人(例如 Haskell、Lisp)中是否有任何相关的东西可以移植甚至只是用于灵感(因为我什至没有任何关于如何开始的线索)这样的实现)?换句话说:如何为相互递归的功能数据结构生成有意义的差异 pretty-print ?
最佳答案
将数据结构转换为人类可读形式(然后对该表示进行操作)的一种方法是使用 Core.Std
s-表达式;它们基本上是在 LISP s 表达式和 Core.Std
之后建模的具有将数据从 s 表达式转换为 s 表达式的功能(以及用于自动化大多数无聊部分的语法扩展)。您可以在 Real World OCaml 的第 17 章中找到一个很好的概述。
对您的应用程序最重要的是,已经有计算 s 表达式之间差异的功能(您也可以漂亮地打印它们,然后对它们使用普通的文本差异)。此功能可以在 Core_extended.Std.Sexp.Diff
中找到.
例子:
open Core.Std (* basic Sexp functionality. *)
module XSexp = Core_extended.Std.Sexp (* for Sexp diffs. *)
type example = {
a: string;
b: int;
c: float;
} with sexp (* syntax extension *)
let v1 = { a = "foo"; b = 1; c = 3.14 }
let v2 = { a = "bar"; b = 2; c = 3.14 }
let print_sexp s = print_endline (Sexp.to_string_hum s)
let sexp_diff s1 s2 =
match XSexp.Diff.of_sexps ~original:s1 ~updated:s2 with
None -> ""
| Some(diff) -> XSexp.Diff.to_string diff
let main () =
let s1 = sexp_of_example v1 in
let s2 = sexp_of_example v2 in
print_endline "=== first sexp ===";
print_sexp s1;
print_endline "=== second sexp ===";
print_sexp s2;
print_endline "=== print_diff output ===";
XSexp.print_diff ~oc:stdout ~original:s1 ~updated:s2 ();
print_endline "=== sexp_diff output ===";
print_endline (sexp_diff s1 s2)
let () = main ()
在这里,
print_diff
是一个预定义的函数,用于将差异打印到 channel 和 sexp_diff
是一个简单的自定义函数,它使用 Sexp.Diff
以字符串形式返回差异。使用 corebuild -pkg core_extended example.native
构建程序后(或 .byte
,或使用 ocamlbuild 和必要的参数),运行程序应该产生以下输出:=== first sexp ===
((a foo) (b 1) (c 3.14))
=== second sexp ===
((a bar) (b 2) (c 3.14))
=== print_diff output ===
a
- foo
+ bar
b
- 1
+ 2
=== sexp_diff output ===
a
- foo
+ bar
b
- 1
+ 2
关于ocaml - 自动为递归数据结构生成差异 pp,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34806521/