8.6 Exercise

Ex.

Exercise 8.1

Today's exercise is to write a pretty-printer for charts. Remember that the chart is still in the database after the parse: chart_recognize_bottomup([vincent,shot,marsellus]),listing(arc). Write a failure-driven loop that reads out the chart from the database and prints it out (as in our examples in the text, or upside down - as you like it).

[Hints:]

In SWI Prolog, the predicate format/2 can be used for formatted output (you have seen this before in Exercise 3.4). format(+Format, +Arguments) gets two arguments: a so-called format-string, and a list of arguments. The format string specifies how to print the arguments, here you can also include line breaks, tabs tops, and some more formatting commands. The easiest thing you can do, is print out an argument as with write/1: format("~w",[hiFans]) . The first (and only) ~w in the format string tells format/2 to give its first argument to write/1. If you have more than one argument, the n-th ~w refers to the n-th argument. You can insert linebreaks (~n) or plain text in the format string like this:

format("~nDer erste ist ~w, der zweite ~w und der dritte steht in einer neuen Zeile:~n~w.",[tick,trick,track]). .

How do I get the format string? This is easy. Remember that strings are lists of characters. You can use append/3 or the list constructor | for building them. A pointless example using append/3 would be the following: append("~nHere are the ducks: ","~w,~w,~w",FString),format(FString,[tick,trick,track]). You can see that the lenght of the argument list specifies the number of ~ws that have to be in the format string. If you want to save some calls of append/3, try this: format([126,110,126,119|" was here!"],[lala]) This works because [126,110,126,119] is another way of writing the string "~n~w" (Remember that char_code/2 gives you the character code of an atom).

Finally, tabs tops and padding. Tabs are set by inserting ~n| with n being some column number in the format string (see the SWI documentation). For example: format("~nThree ducks:~n~20|~w~40|~w~60|~w",[tick,trick,track]). You can fill up the space between two tabs with characters like - or = by including ~`-t or ~`=t, respectively: format("entry1 ~`-t~20| entry2~`=t ~40| entry3 ~60|",[]). This will be useful for drawing the charts.

Ein weiterer Kommentar...

Die allgemeine Idee ist es, die Kanten beim Parsen hinten an die Datenbank anzufügen (assertz), so dass die älterten Kanten zuoberst in der Datenbank stehen. Diese lese ich der Reihe nach aus und zeichne sie wie folgt. Die Position jedes Knotens und Wortes multipliziere ich mit einem Faktor (sagen wir 5). Dann sieht die Chart so aus:

(Pos        0        5        10        15        20        25        30)
 
        0        mia         1        shot         2        vincent        3
 
        |------pn-------|

Dann zeichne ich die erste Kante und merke mir in einem dynamischen Prädikat den rechten Rand meiner aktuellen Zeile (also 10). Wenn ich nun als nächste Kante eine Kante bekomme, die rechts vom aktuellen Rand beginnt (also an Pos 10 oder größer), zeichne ich sie dazu und setze den Rechten Rand entsprechend hoch, z.B.:

(Pos    0       5       10      15      20      25      30)
 
        0       mia     1       shot    2       vincent 3
 
        |------pn-------||--------------vp--------------|

Nun ist der Rechte Rand 30. Wenn ich jetzt eine Kante bekomme, deren Startposition kleiner als 30 ist, gehe ich in eine neue Zeile, setze den Rechten Rand auf 0 und zeichne die Kante:

(Pos    0       5       10      15      20      25      30)
 
        0       mia     1       shot    2       vincent 3
 
        |------pn-------||--------------vp--------------|
        |------np-------|

Nun ist der Rechte Rand 10. Und so weiter. Damit bekommt man eine ganz gut aussehende Chart. Man kann noch ein Bisschen mit den Abständen spielen, da der Computer nicht an dieselbe Position zeichnen kann und sich die Kanten dann um einen Punkt nach rechts verschieben, aber das ist nicht tragisch. Nun gebe ich euch meinen Code, der die Worte zeichnet und ihr könnt entlang diesem Beispiel das Prädikat 'print_arcs' ergänzen.

:- ['passive_chart_bottomup.pl','ourEng.pl'].
 
% der rechte Rand
:- dynamic(chartTab/1).
 
% der Faktor, der die Pos. bestimmt.
tabulator(7).
 
print_chart :-
        nl,
        print_words,
        retractall(chartTab(_)),
        assert(chartTab(0)),
        print_arcs.
 
print_chart.
 
 
print_words :-
        retract(scan(From,_,Word)),
        tabulator(Tabulator),
        NodeTab is 2 * From * Tabulator,
        % mache aus der Zahl NodeTab den String NodeTabChar
        number_codes(NodeTab,NodeTabChar),
        WordTab is NodeTab + Tabulator,
        number_codes(WordTab,WordTabChar),
        % erzeuge z.B. "~14|~w" für NodeTab=14
        append([126|NodeTabChar],"|~w",FS1),
        append([126|WordTabChar],"|~w",FS2),
        append(FS1,FS2,FS),
        format(FS,[From,Word]),
        fail.
 
print_words :- nl.
 
 
% Von Euch zu ergänzen!!!
print_arcs.
 
% Aufruf
%:- chart_recognize_bottomup([mia,who,shot,the,robber,died]),print_chart.

Exercise 8.2

[Mid Term Project]

In Exercise 8.1, the chart was printed after parsing. Alternatively, you can print out the chart incrementally during the parsing process. Modify the respective predicates in passive_chart_bottomup.pl . If the visualization is too fast, you can slow it down using the predicate sleep/1: write(a),flush_output,sleep(2),nl,write(b). The statement flush_output is important for incremental output. If you leave it away, Prolog might buffer the output some and print it all at once: write(a),sleep(2),nl,write(b).


Kristina Striegnitz, Patrick Blackburn, Katrin Erk, Stephan Walter, Aljoscha Burchardt and Dimitra Tsovaltzi
Version 1.2.5 (20030212)