2

x:int = if true then 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の初心者であり、オンラインで文字列に変換することについて何も見つけることができませんでした. ありがとう!

4

3 に答える 3

5

ml 構文を使用して、シンボリック式をきれいに出力したいとします。いわゆるsexpを処理するライブラリがありますが、私はそれらを使用したことはありません.

すでに持っているものに多少近いと思いますが、コードにいくつかの構文エラーがあります。ギャップを埋めるのに役立つアドバイスをたくさんします。

まず、OCaml の構文について:

関数の引数に括弧を使用する必要がないことを思い出してください。関数定義の一般的な構文は次のとおりです。

let fun_name arg1 arg2 arg3 = function_body

あなたが書くなら

let fun_name (arg1,arg2,arg3) = ...

実際には、それ自体が 3 つの値のタプルである 1 つの引数をとる関数を定義しています。

let ... in式の中で、最上位の値を定義するときと同じように (上記で行ったように) 、構文を使用してローカル値を定義できます。これらの値の定義が相互に依存していない場合は、and複数の値の定義の間でキーワードを使用できます。

例えば、

let x = 1 
and y = "a" in
...

x2 つの値を定義yし、後続のコードで使用できます。

あなたのコードで

あなたが持っている型は、例で与えたような式を定義できる小さな記号式言語を与えます:

「x:int = true の場合は 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( type の 3 タプルを取る関数string * exp * exp)
  • formatDec1( type の 3 タプルを取る別の関数exp * exp * exp)
  • formatIf(と同じformatDec1)

関数定義でキーワードrecを使用toStringし、関数が再帰的であることを示しています。私の意見では、上記の 3 つの関数は必要ありません (それらは最初の割り当ての一部ですか、それとも自分で定義したのでしょうか?)、toString関数と文字列の連結だけが必要です。

型のAppexpは非常に一般的です。任意の数の引数の適用を定義できるため、文字列変換コードはその可能性を考慮に入れる必要があります。それを処理するために、いくつかのリスト関数(fold_left頭に浮かぶ)を使用できます。

于 2012-11-13T10:06:45.050 に答える
4

印刷関数を自動的に生成するのに役立つderivingという名前のプロジェクトもあります。使っていませんが、良さそうです。

このようなものがベースの OCaml コンパイラに追加されるのを見るのはとてもクールでしょう。Haskell (「派生」という名前の由来) では非常にうまく機能します。

于 2012-11-12T20:05:23.840 に答える
2

タイプ (または印刷可能なタイプのレコードまたは製品で構成される集約タイプ) に対して、独自の印刷ルーチンを実装する必要があります。

出力される引数に加えて、出力関数を受け入れるモジュールPrintf%aの変換仕様を使用したい場合があります。

インタラクティブなocamlトップレベル インタープリターを使用している場合は、#install_printer トップレベル ディレクティブを使用することをお勧めします。

あなたのコードでは、再帰的に呼び出す必要がありますformat(And(e1, e2)パターンの場合など)。

文字列に出力するには、Printf.sprintfまたはFormat.sprintfとその仲間を使用します。Printfとモジュールの両方Formatが他の機能を提供します (チャネルへの出力、バッファーへの出力、文字列への出力など)。

于 2012-11-12T19:49:07.523 に答える