如何在Ocaml中将非内置类型转换为字符串?

如何在Ocaml中将非内置类型转换为字符串?,ocaml,Ocaml,我试图编写一个模块,将x:int=if-true和3-else-5转换为字符串 这是我目前掌握的代码 module Ast = struct type typ = Bool | Int type var = A | B | C | D | E | F type exp = Const of int * typ | App of string * exp list | If of exp * exp * exp | And of

我试图编写一个模块,将x:int=if-true和3-else-5转换为字符串

这是我目前掌握的代码

module Ast =
struct

type typ = Bool | Int
type var = A | B | C | D | E | F
type exp = Const of int * typ
           | App of string * exp list
           | If of exp * exp * exp
           | And of exp * exp
           | Or of exp * exp
       | Id of var * typ * exp


let rec toString (t) =
    let formatDec1(va,ty,e) = ???
    match t with
    Const(n, _) -> print_int n
      | App(id, [e1; e2]) -> formatter(" " ^ id ^ " ", e1, e2)
      | App(id, [e1]) -> formatter(" " ^ id ^ " ", e1, Const(0, Int))
      | App(id, _) -> formatter(" " ^ id ^ " ", Const(0, Int), Const(0, Int))
      | If(e1, e2, e3) -> formatIf(e1, e2, e3)
      | And(e1, e2) -> formatter(" && ", e1, e2)
      | Or(e1, e2) -> formatter(" || ", e1, e2)
      | Id(va,ty,e) -> formatDecl(va,ty,e)
end

我还是OCaml的初学者,在网上找不到任何关于转换为字符串的信息。谢谢

您必须为您的类型(或聚合类型,由可打印类型的记录或产品组成)实现自己的打印例程

您可能需要使用模块的
%a
转换规范,该模块除了要打印的参数外,还接受打印功能

如果使用交互式
ocaml
顶级解释器,您可能需要使用
#安装(印表机
)

在代码中,您希望递归调用
格式
(例如,对于
和(e1,e2)
模式案例)


要打印到字符串,请使用
Printf.sprintf
.sprintf
和friends。
Printf
Format
模块都提供了其他功能(打印到频道、缓冲区、字符串等)

还有一个名为的项目,可以帮助自动生成打印功能。我没用过,但看起来不错


看到这样的东西被添加到基本的OCaml编译器中会非常酷。它在Haskell中工作得非常好(“派生”这个名字就是从这里来的)。

您希望使用ml语法漂亮地打印符号表达式。有一些库可以处理所谓的sexp,但我从未使用过它们,我无法评论它们的使用,而且这可能不是你想要的,因为它会回避练习的目的


我认为您与已有的有些接近,但代码中存在一些语法错误。我会给你一些建议来帮助你缩小差距

首先,关于OCaml语法:

回想一下,函数参数不需要使用括号。函数定义的一般语法为:

let fun_name arg1 arg2 arg3 = function_body
如果你写信

let fun_name (arg1,arg2,arg3) = ...
实际上,您正在定义一个使用1个参数的函数,该参数本身就是一个包含3个值的元组

在表达式中,可以使用
let。。。在
construct中,就像定义顶级值一样(就像我上面所做的)。如果这些值定义不是相互依赖的,则可以在多个值定义之间使用
关键字

比如说,

let x = 1 
and y = "a" in
...
将定义两个值
x
y
,可在后续代码中使用

在您的代码中

您使用的类型提供了一种符号表达式语言,您可以使用该语言定义表达式,如示例中所示:

“x:int=如果为真,则3或5”应为:

Id("x", 
   Int, 
   (If (Const (1, Bool), 
        Const (3, Int), 
        Const (5, Int))))
实际上,您需要递归地遍历该值,并将返回的字符串组合成一个更大的字符串。或者,您可以使用字符串列表,并在末尾执行字符串连接。 看看这个例子,您可能会看到这是如何工作的:

"x" ^ (":" ^ "int") ^ "=" ^ ("if" ^ ("true") ^ "then" ^ ("3") ^ ("5"))
您可以在上面的中看到不同的子表达式模式。我用括号表示它们

在toString函数中,有3个未定义的值:

  • formatter
    (一个采用3元组类型的函数
    string*exp*exp
  • formattec1
    (另一个函数采用类型为
    exp*exp*exp
    的三元组)
  • formatIf
    (与
    formatDec1
    相同)
您在
toString
函数定义中使用了关键字
rec
,表示函数是递归的。在我看来,您不需要上面的3个函数(它们是您初始赋值的一部分,还是您自己定义的?),只需要
toString
函数和字符串连接


您的
exp
类型的
App
臂非常通用:您可以定义任意数量参数的应用程序,因此您的字符串转换代码应该考虑这种可能性。您可以使用一些列表函数(
左折
想到)来处理它。

谢谢您,但我刚刚发现需要先将整个内容转换为字符串,这是一个完全不同的主题。很抱歉。根据我刚才查看的文档,派生项目也可以从值生成字符串。(另一方面,我不确定该项目是否已更新为最新的OCaml。)为我使用4.00.1派生工作。我们也不要忘记sexplib。太棒了,很高兴听到衍生是最新的!我使用sexplib,但我认为它是一种外部化数据的方法,而不是一种打印数据的方法。但是,它可读性很强,我经常会在最后查看它。派生中的to_字符串函数太复杂了。我认为我们不需要在初学者的课堂上使用这样的东西。有没有更直接的方法将非原语转换为字符串?学习ocaml一直令人沮丧。对于初学者来说,没有足够的资源。谢谢你的帮助谢谢,但我刚刚发现我需要首先将整个内容转换为字符串,这是一个完全不同的主题。很抱歉。我尝试了Printf.sprintf(“%a”),但它是(单元->'\u a->string)->'\u a->string。我从来没有遇到过像unit->'a这样的东西。你能给我举个例子吗?这是我第一次使用printf。
%a
需要两个参数(第一个是函数)。阅读
Printf
Format
模块文档。在您的示例中会得到什么结果?例如“x:int=if true,那么3 else 5”。不确定到目前为止我使用的toString函数是否正确。所以您需要打印精美的符号表达式,并使用ml语法。有一些库可以处理所谓的sexp,但我不知道字符串的表示方式是怎样的。您与已有的有些接近,但代码中存在一些语法错误