2011-09-11 8 views
4

私は以下マーキュリーコードをコンパイルするとき、私は、コンパイラからこのエラーを取得する:Mercury:高次データ型の決定論を宣言する方法は?

In clause for `main(di, uo)': 
    in argument 1 of call to predicate 
    `test_with_anonymous_functions.assert_equals'/5: 
    mode error: variable `V_15' has 
    instantiatedness `/* unique */((func) = 
    (free >> ground) is semidet)', 
    expected instantiatedness was `((func) = 
    (free >> ground) is det)'. 

私はコンパイラが言っていることと思いますが、あなたがタイプtest_caseを宣言したとき、あなたはそう、決定論を指定していない」であります私はあなたがdetを意味すると仮定しましたが、それからsemidetラムダを渡しました。 "

私の質問:

  • タイプの決定論を宣言するための構文は何ですか?私が試した推測では、すべて構文エラーが発生しています。
  • /* unique */TestCaseのインスタンス化の意味は何かを説明できますか?それは与えられた&とインスタンス化の間の不一致を引き起こすでしょうか?
  • mainにラムダを宣言する方法はあまりありませんか?私はラムダ内でコードを行うのと同じくらい多くのラムダ宣言をしています。

コード:

% (Boilerplate statements at the top are omitted.) 

% Return the nth item of a list 
:- func nth(list(T), int) = T. 
:- mode nth(in,  in) = out is semidet. 
nth([Hd | Tl], N) = (if N = 0 then Hd else nth(Tl, N - 1)). 

% Unit testing: Execute TestCase to get the 
% actual value. Print a message if (a) the lambda fails 
% or (b) the actual value isn't the expected value. 
:- type test_case(T) == ((func) = T). 
:- pred assert_equals(test_case(T), T, string, io.state, io.state). 
:- mode assert_equals(in,   in, in,  di,  uo) is det. 
assert_equals(TestCase, Expected, Message, !IO) :- 
    if Actual = apply(TestCase), Actual = Expected 
    then true % test passed. do nothing. 
    else io.format("Fail:\t%s\n", [s(Message)], !IO). 

main(!IO) :- 
    List = [1, 2, 3, 4], 
    assert_equals(((func) = (nth(List, 0)::out) is semidet), 
       1, "Nth", !IO). 

答えて

3

これは、同様のこつを得るために私にしばらく時間がかかりました。

問題は、高次用語のモードがではなく、タイプがであることです。したがって、型の決定論を宣言する構文はありません。高次の項の決定論はモードで運ばれる。

例では、assert_equalsの最初の引数は、タイプがtest_case(T)ですが、モードはinです。これは、その機能がsemidetであることが失われることを意味します。あなたが渡している関数がdetだったら、実際にコンパイルされているか正しく動作しているかわかりません。その場合でもモードは実際にはinであってはなりません。ここで

は例です:あなたが見ることができるように

:- pred apply_transformer(func(T) = T, T, T). 
:- mode apply_transformer(func(in) = out is det, in, out). 
apply_transformer(F, X0, X) :- 
    X = F(X0). 

main(!IO) :- 
    apply_transformer((func(S0) = S is det :- S = "Hello " ++ S0), 
         "World", Msg), 
    print(Msg, !IO), 
    nl(!IO). 

apply_transformerへの最初の引数の型は、それが高階関数であると言う一つの引数を取り、同じ型の結果を返します。実際に関数パラメータがモードinを持ち、関数の結果がモードoutであり、その決定性がdetであると言うモード宣言です。

エラーメッセージの/*unique */ビットは、コンパイラがそれがユニークな値だと思っていると言います。あなたが普通のio州以外のユニークなモードを使用していないので、それが問題かどうかはわかりません。

ラムダの構文に関しては、私はあなたが残念なことにどんなこともできるとは思わない。私はMercuryのlambdaの構文がかなり不満足であることを発見しました。彼らは非常に冗長なので、私は通常、最も軽いラムダ以外の名前付き関数/述語を作るだけです。



+0

ありがとう、ベン。 – Evan

+0

@エヴァン:私の答えに追加するのを忘れましたが、高次の用語の複雑なモードのためのモードエイリアスを作成することもできます(これは私の問題を解決しました)。私は同じタイプの高次の引数を取る数十の述語を持つモジュールに対してこれを一度行なった。私はタイプとモードをモジュールの上に宣言し、その中でそれらを使用しました。 – Ben

+0

@Evan:ねえ、あなたは http://stackoverflow.com/questions/13896296/creating-a-deterministic-finite-automata-dfa-mercury を見てみたいものです - これを行うには何もポストは、エバンに注目を集めるためだけに – Dieter

4

ベンは、私はマーキュリーは関数が(それは関数が決定論的であるべきことを賢明です)デフォルトでは決定論的であると仮定していることを追加したい、

権利です。これは、決定論を宣言しなければならない述語には当てはまりません。これにより、他の関数や述語よりも確定的な関数を使った高次のプログラミングを簡単に行うことができます。

このため、ラムダ式を少し簡潔にすることができます。また、頭部の変数Sを本文に置き換えることによって、ラムダ式の本文を頭に移動することもできます。

apply_transformer((func(S0) = "Hello " ++ S0), 
        "World", Msg), 
2

2番目の質問に答えるために、エラーメッセージの/* unique */はあなただけで構築したラムダ項でassert_equalsへの呼び出しの最初の引数を参照しています。これは、この用語が使用される唯一の場所です。したがって、その参照は呼び出し時に一意です。

固有のinstは地上のinstと一致しますが、この場合、一意性は不一致にはなりません。それは問題である決定論です。

関連する問題