7

それらが等しくない場合に比較してエラーメッセージを表示するテスト関数を実装しようとしています:

exception AssertionErrorException of string

fun assert(testName, actual, expect) : bool =
    if actual = expect
    then true
    else raise (AssertionErrorException (testName ^ " failed. actual: " ^ actual 
                ^ ", expect: " ^ expect ));

残念ながら、文字列以外のパラメーターで呼び出すと機能しません。

assert("test1", SOME [], NONE);

コンパイルできず、エラー メッセージは次のとおりです。

Error: operator and operand don't agree [tycon mismatch]
  operator domain: string * string * string
  operand:         string * 'Z list option * 'Y option
  in expression:
    assert ("test1",SOME nil,NONE)

修正方法は?

4

3 に答える 3

7

makestringは、Standard ML の初期のドラフトの一部に存在していましたが、最終バージョンの前に削除されました。Poly/ML はこれをPolyML.makestringとして保持し、これは構造化型を含むあらゆる型で機能します。

この特定の例では、次のように書くことができます

fun assert(testName, actual, expect) =
if actual = expect
   then true
   else raise AssertionErrorException(testName ^ " failed. actual: " ^
                PolyML.makestring actual ^ ", expect: " ^
                PolyML.makestring expect);

そう

 assert("test1", SOME [], NONE);

版画

Exception-
AssertionErrorException "test1 failed. actual: SOME [], expect: NONE"
   raised

実際の型と期待される型は等価型であり、これによりコンパイラに値を適切に出力するのに十分な情報が提供されるため、これはたまたま機能します。ただし、通常、PolyML.makestringがポリモーフィック関数に含まれている場合、出力されるのは「?」だけです。解決策は、特定の型を文字列に変換する関数である追加のパラメーターを渡すことです。

fun assert(testName, actual, expect, toString) =
   if actual = expect
   then true
   else raise AssertionErrorException(testName ^ " failed. actual: " ^
                toString actual ^ ", expect: " ^ toString expect );

次に、特定の値を文字列に変換する関数を渡す必要があります。Poly/ML では、これはPolyML.makestringになります。

assert("test2", (1,2,3), (1,2,4), PolyML.makestring);

版画

Exception-
   AssertionErrorException
  "test2 failed. actual: (1, 2, 3), expect: (1, 2, 4)" raised

別の SML 実装を使用している場合でも、同じことを行い、特定の型に対して独自の変換関数を渡すことができます。

assert("test2", (1,2,3), (1,2,4),
     fn (a,b,c) =>
        String.concat["(", Int.toString a, ",", Int.toString b,
                      ",", Int.toString c, ")"]);

実際には、前の回答で説明した型クラスを実装しています。

于 2013-10-14T12:48:11.913 に答える
7

Haskell では、型を型クラスのインスタンスにしShow、関数のオーバーロードされたバリアントを実装してから、 .ではなくshow :: Show a => a -> String出力します。残念ながら、そのような型クラスは標準 ML には存在しないため、プリティプリントするすべてのデータ型に対して、オーバーロードされていない独自のバリアントを作成する必要があります。show xxshow

一部の SML コンパイラ (少なくとも Moscow ML)makestringは、複合型ではなく、組み込み型のサブセットに対してのみ機能するオーバーロードされた関数をサポートしています。たとえばmakestring 2makestring 2.0両方とも機能しますが、makestring (0,0)機能しません。編集makestring:David Matthewsは、PolyMLの方が優れていることを以下の回答で指摘しています。)

エラーをきれいに出力する一般的なアサーション関数を作成したい場合、値をアサートしたい型ごとにコンストラクターを持つデータ型を作成することができます。これは、C の「ユニオン」タイプのように機能します。

exception AssertionError of string
datatype assert = AssertInt of int
                | AssertReal of real
                | AssertBoolBool of bool * bool
                | ...

fun assertPP (AssertInt i) = Int.toString i
  | assertPP (AssertReal r) = Real.toString r
  | assertPP (AssertBoolBool (b1,b2)) =
    String.concat ["(", Bool.toString b1, ", ", Bool.toString b2, ")" ]
  | assertPP (...) = ...

fun assert (testName, actual: assert, expect: assert) =
    actual = expect  (* ML infers equality for constructors *)
    orelse raise AssertionError (String.concat
        [ testName, " failed. actual: ", assertPP actual,
          ", expect: ", assertPP expect, "." ])

これは、過負荷に対する貧乏人の代替品です。

于 2013-10-13T13:53:26.733 に答える