4

タイプ t = Test of int * t ref を作成しました

t型のオブジェクトを作成するには?

4

1 に答える 1

11

デルナンが言ったように、循環値を使用できます:

let rec x = Test (0, ref x)

再帰は一般に関数の定義に使用されますが、特定の値に対しては可能です。これは一般的には不可能です。ドキュメントに記載されている制限があります。

この値はヒープに割り当てられているため、再帰的に簡単に使用できます。最初に「テスト」コンストラクターにスペースを割り当ててから、「x」に割り当てられたコンストラクターのアドレスを使用してフィールドを定義できます。まだ完全に定義されていない値を指している場合。関数、遅延値、ペア、レコードなどはすべてこのパターンに従います。もちろん、仕様はそれほど低レベルではなく ("heap-allocated" は OCaml マニュアルでは定義されていません)、もう少し制限的な構文仕様があります。

値の再帰によって値をブートストラップしたら、より精巧な値を作成できます。

let rec x = Test (0, ref x)
let y = Test (1, ref x)
let (Test (_, r)) = x in r := y

直接行うこともできます

let rec x = Test (0, ref y)
and y = Test (1, ref x)

実際には推奨されませんが、 によって生成される「ダミー値」を使用することも可能ですObj。これがQueue標準ライブラリのモジュールの実装方法です。

この定義の問題点は、値が循環的であることです。そのような値の「テール」を反復することを計画している場合、問題になる可能性があります。構造体の「末尾の長さ」を追跡するために int フィールドを使用する場合 (0 は、参照が従うべきではないダミー ポインターであることを意味します)、これはまさにQueueモジュールの実装方法です。

可能な他のオプションがあります。たとえば、オプション type を使用してテール ポインターの null 可能性を明示するモデルを使用できます。

type t' = Test of int * t' option ref

let x = Test (0, ref None)
let y = Test (0, ref (Some x))

let rec length (Test (_, tail)) =
  match !tail with
  | None -> 0
  | Some tl -> 1 + length tl 

その場合、型をブートストラップするための再帰は必要ありません。それでNone十分です。もちろん、オプション型には間接性があるため、これには適度なパフォーマンス コストが伴います。

PS : このようなコンストラクターが 1 つの型の場合は、レコード型を使用したほうがよい場合があることに注意してください。

type t = {
  field : int;
  tail : t ref;
 }
于 2010-12-04T16:41:39.540 に答える