SML/NJ インタプリタの表示設定を変更する

SML/NJのインタプリタは, 入力した式の評価結果をいい感じに表示してくれるので便利ですが,
複雑なデータは適当に省略されて表示されてしまいます.

たとえばこんな感じ.

- val xs = List.tabulate (15,fn x=>x);
val xs = [0,1,2,3,4,5,6,7,8,9,10,11,...] : int list

あと少しくらいがんばって欲しいワケですがバッサリ切られます

変更方法

この表示方法は,処理系専用に提供されているstructureから設定すれば変更することが出来ます.

- Control.Print.printLength := 15; (* 表示するリストの長さを伸長 *)
val it = () : unit
- val xs = List.tabulate (15,fn x=>x);
val xs = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] : int list

おk

設定できる項目一覧

(* 表示は多少弄ってるが言いたいことは伝わる。多分。 *)
structure Control.Print :
  sig
	val printDepth : int ref  (* コンストラクタのネストをどこまで展開するか *)
	val printLength : int ref (* リストの長さ *)
	val stringDepth : int ref (* 文字列の長さ *)
	val intinfDepth : int ref (* LargeIntの表示桁数 *)
	val printLoop : bool ref  (* ループ検出を行うか *)
	val signatures : int ref  (* ネストしたシグネチャの展開段数 *)
	val printOpens : bool ref (* open したときシグネチャを表示するか *)
	val linewidth : int ref   (* 一行の長さ(これを超えると改行する) *)
	(* インタプリタの表示関数 *)
	val out : {flush:unit -> unit, say:string -> unit} ref
	val say : string -> unit
	val flush : unit -> unit
  end

大体名前から明らかですね. あんまり明らかじゃないモノを以下で解説します.

printLoop

	val printLoop : bool ref  (* ループ検出を行うか *)

これはデータ構造の循環構造を検出して, それと分かる表示をしてくれるオプションです.

datatype Loop = X | T of int * Loop ref
val xr = ref X;
val xs = T (1, xr);
xr := xs;
- xs; (* xs は [1..] のような遅延リストになる *)
val it = T (1,ref (T (1,%0)) as %0) : Loop
(* %0 は内部に自身への参照を持っていると分かる *)

これをオフにすると….

- Control.Print.printLoop := false;
- xs;
val it = T (1,ref (T (1,ref (T (1,ref (T (1,ref (T (1,ref #))))))))) : Loop
(* 深さ(or長さ)の制限まで展開し続けます *)

表示関数のフックと書き換え

	val out : {flush:unit -> unit, say:string -> unit} ref

インタプリタが表示に使う関数をこれで書き換えることが出来ます.

(* インタプリタの出力をログファイルに書き出す例 *)
let val f = TextIO.openIn "smlnj.log"
in Control.Print.out := {flush=fn()=>TextIO.flushOut f, say=fn s=> TextIO.output(f,s)}
end

.oO(ファイルを閉じてないけど。ま、いいか)

ref

マニュアル
intinfDepth の記載が無い件…