タイプ t = Test of int * t ref を作成しました
t型のオブジェクトを作成するには?
デルナンが言ったように、循環値を使用できます:
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;
}