Prolog にて、ローンパターン(Loan Pattern) を簡潔に実装したい


`Prolog` にて `ローンパターン(Loan Pattern)` を後述のように実装しましたが、より簡潔に書けないものでしょうか？

ここでの `ローンパターンは、 リソースの解放を忘れないようにする仕組み` を意図しています。 ( [C#でいう using
ステートメント](https://msdn.microsoft.com/ja-jp/library/yh598w02.aspx) 、 [Javaでいう
try-with-resources
ステートメント](http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html)
が近いかもしれません。 )

* * *

特に以下の点について、疑問が残りました。

  * 毎度 `print_each` のような定義をしない方法はないか
  * `repeat` の部分を簡潔に書けないか？
  * (そもそもこれはローンパターンになっているのか？)

[code]

    main :-
        writeln('# Open!'),
    
        % 'test.txt' を開き、print_each 述語で処理する。
        open_each('test.txt', print_each),
    
        writeln('# Closed!').
    
    % ファイルを読み込むごとに呼ばれる述語
    % 【疑問点】毎度 print_each の定義しなければならないものか？
    print_each(Term) :-
        % some process here...
        % 
        printf('%t', [Term]), nl.
    
    open_each(FileName, Do) :-
        open(FileName, read, Stream),
    
        % 【疑問点】とくに以下は簡潔に書けないか？
        repeat,
        ( at_end_of_stream(Stream)
        ->  !
        ;   read(Stream, Term),
            call(Do, Term), 
            fail
        ),
    
        close(Stream).
    
    :- main, halt.
    
[/code]

以下は test.txt の中身です。

[code]

    text(foobar).
    text(fuba).
    text(abafu).
    text(syzzy).
    
[/code]

実行例は以下のようになります。

[code]

    # Open!
    text(foobar).
    text(fuba).
    text(abafu).
    text(syzzy).
    # Closed!
    
[/code]

環境: SWI-Prolog version 5.10.4 for amd64 です。

※ より Prolog らしいコードや用語の誤りなどありましたらコメントなどでご指摘お願いします




`throw` and `catch` はいかがでしょうか。これは、Java などの `try 〜 catch 〜 finally 〜`
と同じ様なものだと思います。

[code]

    main :-
      writeln('# Open!'),
      open_each('test.txt', read_and_print_term),
      writeln('# Closed!').
    
    read_and_print_term(Stream) :-
      at_end_of_stream(Stream) -> !;
      read(Stream, Term),
      writef('%t', [Term]), nl,
      read_and_print_term(Stream).
    
    %% 追記: 以下は必要ありませんでした    
    %%read_and_print_term :- throw(_).
    
    open_each(FileName, Do) :-
      open(FileName, read, Stream),
      catch(call(Do, Stream), _, (write('# Error!'), nl)),
      close(Stream).
    
    :- main, halt.
    
[/code]

例えば、`text.txt` が以下の様になっている場合、

[code]

    text(foobar).
    text(fuba).
    Hello World!
    text(abafu).
    text(syzzy).
    
[/code]

実行結果は以下の様になります。

[code]

    # Open!
    text(foobar)
    text(fuba)
    # Error!
    # Closed!
    
[/code]

ただ、質問者様のプログラムではエラーはスキップしてファイルを最後まで読み込む様な仕様に見えるので、これでは期待に添わないかもしれません。ご参考程度にどうぞ。

