/* The following comment was added by Kari Laitinen on 15.3.2005 This is one of the Prolog programs of which an experimental software maintenance tool called InName is made. InName is a disabbreviation tool with which it is possible convert abbreviated names of C/C++ programs to more understandable, natural names. The Prolog source programs of the InName tool are now declared "Open Source" programs. People who have contributed to the original development of these programs include Kari Laitinen http://www.naturalprogramming.com Neil Rowe U.S. Naval Postgraduate School Markku Heikkila Currently works at Nokia. Jorma Taramaa Currently works at Nokia. The InName tool was developed at VTT Electronics, a division of the Technical Reseach Centre of Finland. The work was funded by VTT Electronics and the EU. It is the wish of the original developers that the above names will be mentioned if these programs are exploited in the development of other disabbreviation tools. A description about the InName tool and theoretical discussion related to it can be found at Laitinen, K., Taramaa, J., Heikkila, M., and Rowe, N. C.. Enhancing Maintainability of Source Programs through Disabbreviation. The Journal of Systems and Software, Vol. 37, No. 2, 1997, pp. 117 - 128. The text of the original file begins below. */ /*--------------------------------------------------------------------------- VTT Electronics Quintus Prolog source program Embedded Software AMES / InName project Kari Laitinen File: inname_second_pass.pro Version: 0.3 Status: draft Accepted by: File history: 9.3.94 v0.0 File created as "test.pro" Kari Laitinen 28.4.94 v0.1 File renamed as "inname.pro" Kari Laitinen 8.8.94 v0.2 File modified to "inname_second_pass.pro" Kari Laitinen 5.5.95 v0.3 Last modification Kari Laitinen ---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------- TERMINOLYGY: capitalized word A word which starts with an uppercase letter, but is lowercase otherwise. capitalized name A name consisting solely of capitalized words,i.e. capital letters are word separators. name candidate Those names which are generated by the tool and of which the user makes his selection. name substitution The result of deabbreviation and user action. underscored name A name in which underscore characters "_" are used as word separators. -----------------------------------------------------------------------*/ :- no_style_check(single_var). :- ensure_loaded(library(caseconv)). :- ensure_loaded(library(basics)). :- ensure_loaded(library(lists)). :- multifile possible_word_substitution/1, name_candidate/1. :- multifile word_substitution/2, name_substitution/3. :- multifile unknown_name/4, general_counters/2. :- multifile domain_word/1, potential_name/1, potential_substitution/2, previous_name_substitution/2, previously_used_name_substitution_found/0. :- dynamic possible_word_substitution/1, name_candidate/1. :- dynamic word_substitution/2, name_substitution/3. :- dynamic unknown_name/4, general_counters/2. :- dynamic domain_word/1, potential_name/1, potential_substitution/2, previous_name_substitution/2, previously_used_name_substitution_found/0. :- ensure_loaded(library(lists)). get_earliest_unknown_name( Unknown_name, List_of_line_numbers, List_of_all_words, List_of_unknown_words ) :- get_earliest_unknown_name__find_earliest( Unknown_name, List_of_line_numbers, List_of_all_words, Found_list_of_unknown_words ), get_earliest_unknown_name__check_unknown_words(Found_list_of_unknown_words, New_list_of_unknown_words), (( Found_list_of_unknown_words == New_list_of_unknown_words, List_of_unknown_words = Found_list_of_unknown_words ); ( retract( unknown_name( Unknown_name, _, _, _ ) ), List_of_unknown_words = New_list_of_unknown_words, asserta( unknown_name( Unknown_name, List_of_line_numbers, List_of_all_words, List_of_unknown_words ) ) ) ), !. get_earliest_unknown_name__check_unknown_words( [ First_original_unknown_word | Rest_of_original_unknown_words ], [ First_new_unknown_word | Rest_of_new_unknown_words ] ) :- lower( First_original_unknown_word, Lowercased_original_unknown_word ), \+ domain_word( Lowercased_original_unknown_word ), First_new_unknown_word = First_original_unknown_word, get_earliest_unknown_name__check_unknown_words( Rest_of_original_unknown_words, Rest_of_new_unknown_words ), !. get_earliest_unknown_name__check_unknown_words( [ First_original_unknown_word | Rest_of_original_unknown_words ], List_of_new_unknown_words ) :- get_earliest_unknown_name__check_unknown_words( Rest_of_original_unknown_words, List_of_new_unknown_words ), !. get_earliest_unknown_name__check_unknown_words( [], [] ) :- !. get_earliest_unknown_name__find_earliest( Unknown_name, [ First_line_number | Rest_of_line_numbers ], List_of_all_words, List_of_unknown_words ) :- /* This here ----| is called a pair. A special argument type. */ /* | */ /* V */ bagof( First_line_numbers-Unknown_name, (Any_other_line_numbers, Any_all_words, Any_unknowns)^unknown_name( Unknown_name, [ First_line_numbers | Any_other_line_numbers ], Any_all_words, Any_unknowns ), List_of_pairs_of_line_numbers_and_names ), /* It is interesting to note that in the name above I used the word "pair", although I did not know that it is a certain argument-type. */ /* The following call binds the outputs "First_line_number" and "Unknown_name". The subsequent code then binds the outputs "Rest_of_line_numbers" etc. */ keysort( List_of_pairs_of_line_numbers_and_names, [ First_line_number-Unknown_name | _ ] ), unknown_name( Unknown_name, [ First_line_number | Rest_of_line_numbers], List_of_all_words, List_of_unknown_words ), !. make_word_lists_for_name_candidates( [ First_word_in_a_name | Rest_of_words_in_a_name ], [ First_unknown_word | Rest_of_unknown_words ], [ List_of_possible_first_words | Lists_of_possible_other_words ] ) :- lower( First_word_in_a_name, Lowercased_first_word_in_a_name ), (( First_word_in_a_name == First_unknown_word, deabbreviate( Lowercased_first_word_in_a_name, Tentative_list_of_possible_first_words ), (( First_word_in_a_name == Lowercased_first_word_in_a_name, List_of_possible_first_words = Tentative_list_of_possible_first_words ) ; ( make_list_of_words_uppercase( Tentative_list_of_possible_first_words, List_of_possible_first_words ) ) ), make_word_lists_for_name_candidates( Rest_of_words_in_a_name, Rest_of_unknown_words, Lists_of_possible_other_words ) ) ; ( Tentative_list_of_possible_first_words = [ Lowercased_first_word_in_a_name ], (( First_word_in_a_name == Lowercased_first_word_in_a_name, List_of_possible_first_words = Tentative_list_of_possible_first_words ) ; ( make_list_of_words_uppercase( Tentative_list_of_possible_first_words, List_of_possible_first_words ) ) ), make_word_lists_for_name_candidates( Rest_of_words_in_a_name, [ First_unknown_word | Rest_of_unknown_words ], Lists_of_possible_other_words ) ) ). make_word_lists_for_name_candidates( [ First_word_in_a_name | Rest_of_words_in_a_name ], [], [ [ First_word_in_a_name ] | Lists_of_possible_other_words ] ) :- make_word_lists_for_name_candidates( Rest_of_words_in_a_name, [], Lists_of_possible_other_words ). make_word_lists_for_name_candidates( [], _, [] ). duplicate_word_list_with_uppercase_words( [ First_word | Rest_of_words ], [ Uppercase_word, Lowercase_word | Rest_of_duplicated_words ] ) :- upper( First_word, Uppercase_word ), Lowercase_word = First_word, !, duplicate_word_list_with_uppercase_words( Rest_of_words, Rest_of_duplicated_words ), !. duplicate_word_list_with_uppercase_words( [], [] ) :- !. test_append4( Some_list ) :- append4( A,B,C,D, Some_list ), nl, write(A), write(' '), write(B), write(' '), write(C), write(' '), write(D), fail. deabbreviate( Unknown_word, List_of_possible_word_substitutions ) :- /* If we allow empty lists in the appending process we can get all possible substitutions in only one appending call. We do not, however, know how good and fast this approach is. */ /* This approach may be too slow, because the empty lists cause that the algorithm finds the same replacements over and over. We may need to change this so that first it tries the whole word and then splits it into two, three, etc. pieces. */ name( Unknown_word, Unknown_word_as_character_list ), append4( First_abbreviation, Second_abbreviation, Third_abbreviation, Fourth_abbreviation, Unknown_word_as_character_list ), ( ( ( First_abbreviation == [], First_list = [] ) ; ( name( First_abbreviation_as_string, First_abbreviation ), ( ( usual_abbreviation( First_abbreviation_as_string, First_word_abbreviated_in_usual_way ), First_list = [ First_word_abbreviated_in_usual_way ] ) ; ( domain_word( First_abbreviation_as_string ), First_list = [ First_abbreviation_as_string ] ) ; ( dictionary_word( First_abbreviation_as_string ), First_list = [ First_abbreviation_as_string ] ) ; ( word_substitution( First_abbreviation_as_string, First_word_abbreviated_in_domain_style ), First_list = [ First_word_abbreviated_in_domain_style ] ) ) ) ), ( ( Second_abbreviation == [], Second_list = [] ) ; ( name( Second_abbreviation_as_string, Second_abbreviation ), ( ( usual_abbreviation( Second_abbreviation_as_string, Second_word_abbreviated_in_usual_way ), Second_list = [ Second_word_abbreviated_in_usual_way ] ) ; ( domain_word( Second_abbreviation_as_string ), Second_list = [ Second_abbreviation_as_string ] ) ; ( dictionary_word( Second_abbreviation_as_string ), Second_list = [ Second_abbreviation_as_string ] ) ; ( word_substitution( Second_abbreviation_as_string, Second_word_abbreviated_in_domain_style ), Second_list = [ Second_word_abbreviated_in_domain_style ] ) ) ) ), ( ( Third_abbreviation == [], Third_list = [] ) ; ( name( Third_abbreviation_as_string, Third_abbreviation ), ( ( usual_abbreviation( Third_abbreviation_as_string, Third_word_abbreviated_in_usual_way ), Third_list = [ Third_word_abbreviated_in_usual_way ] ) ; ( domain_word( Third_abbreviation_as_string ), Third_list = [ Third_abbreviation_as_string ] ) ; ( dictionary_word( Third_abbreviation_as_string ), Third_list = [ Third_abbreviation_as_string ] ) ; ( word_substitution( Third_abbreviation_as_string, Third_word_abbreviated_in_domain_style ), Third_list = [ Third_word_abbreviated_in_domain_style ] ) ) ) ), ( ( Fourth_abbreviation == [], Fourth_list = [] ) ; ( name( Fourth_abbreviation_as_string, Fourth_abbreviation ), ( ( usual_abbreviation( Fourth_abbreviation_as_string, Fourth_word_abbreviated_in_usual_way ), Fourth_list = [ Fourth_word_abbreviated_in_usual_way ] ) ; ( domain_word( Fourth_abbreviation_as_string ), Fourth_list = [ Fourth_abbreviation_as_string ] ) ; ( dictionary_word( Fourth_abbreviation_as_string ), Fourth_list = [ Fourth_abbreviation_as_string ] ) ; ( word_substitution( Fourth_abbreviation_as_string, Fourth_word_abbreviated_in_domain_style ), Fourth_list = [ Fourth_word_abbreviated_in_domain_style ] ) ) ) ) ), append4( First_list, Second_list, Third_list, Fourth_list, List_of_words ), convert_list_of_words_to_underscored_string( List_of_words, Underscored_string ), \+ possible_word_substitution( Underscored_string ), assertz( possible_word_substitution( Underscored_string ) ), increment_counter( number_of_possible_word_substitutions ), fail. deabbreviate( Unknown_word, List_of_possible_word_substitutions ) :- possible_word_substitution( Some_string ), form_the_list_of_possible_word_substitutions( List_of_possible_word_substitutions ), retractall( possible_word_substitution( _ ) ), reset_counter( number_of_possible_word_substitutions ). deabbreviate( Unknown_word, [] ). form_the_list_of_possible_word_substitutions( [ First_word | Rest_of_words ] ) :- possible_word_substitution( First_word ), retract( possible_word_substitution( First_word ) ), increment_counter( number_of_words_in_list ), counter_is_smaller( number_of_words_in_list, 6 ), form_the_list_of_possible_word_substitutions( Rest_of_words ). form_the_list_of_possible_word_substitutions( [] ) :- reset_counter( number_of_words_in_list ), !. go_candidate( Given_list ) :- retractall( name_candidate( _ ) ), generate_name_candidates_in_database( Given_list ), name_candidate( Word_list ), write_word_list( Word_list ), fail. /* The following rules are called from the user interface. The first two rules handle the case when the List_of_unknown_words is empty. */ generate_list_of_name_candidates( Unknown_name_as_string, List_of_all_words, [], List_of_name_candidates ) :- previous_name_substitution( Unknown_name_as_string, _ ), generate_name_candidates_from_previous_substitutions( Unknown_name_as_string ), list_name_candidates_from_database( List_of_name_candidates ), !. generate_list_of_name_candidates( Unknown_name_as_string, List_of_all_words, [], [ List_of_all_words ] ) :- !. generate_list_of_name_candidates( Unknown_name_as_string, List_of_all_words, List_of_unknown_words, List_of_name_candidates ) :- generate_name_candidates_from_previous_substitutions( Unknown_name_as_string ), make_word_lists_for_name_candidates( List_of_all_words, List_of_unknown_words, List_of_word_lists ), generate_name_candidates_in_database( List_of_word_lists ), /* We have to give the List_of_all_words to the routine which checks potential names, because potential names do not contain any underscores while the Unknown_name_as_string can. */ generate_name_candidates_from_potential_names( List_of_all_words ), generate_name_candidates_from_potential_substitutions( Unknown_name_as_string ), list_name_candidates_from_database( List_of_name_candidates ), !. generate_name_candidates_from_potential_names( Unknown_name_as_list_of_words ) :- make_list_of_words_lowercase( Unknown_name_as_list_of_words, Lowercased_list_of_words ), convert_list_of_words_to_list_of_characters( Lowercased_list_of_words, Unknown_name_as_list ), length( Unknown_name_as_list, Length_of_unknown_name ), Length_of_unknown_name > 2, generate_name_candidates_from_potential_names__backtrack_in_database( Unknown_name_as_list ), !. generate_name_candidates_from_potential_names( _ ) :- !. generate_name_candidates_from_potential_names__backtrack_in_database( Unknown_name_as_character_list ) :- potential_name( Potential_name_as_list_of_words ), /* NOTE: Potential names could be stored as character lists. That would speed up things here. */ convert_list_of_words_to_list_of_characters( Potential_name_as_list_of_words, Potential_name_as_character_list ), can_abbreviate_list1( Unknown_name_as_character_list, Potential_name_as_character_list ), \+ name_candidate( Potential_name_as_list_of_words ), assertz( name_candidate( Potential_name_as_list_of_words ) ), fail. generate_name_candidates_from_potential_names__backtrack_in_database( _ ) :- !. generate_name_candidates_from_potential_substitutions( Unknown_name_as_string ) :- potential_substitution( Unknown_name_as_string, Substitution_based_on_oneline_comment ), \+ name_candidate( Substitution_based_on_oneline_comment ), assertz( name_candidate( Substitution_based_on_oneline_comment ) ), fail. generate_name_candidates_from_potential_substitutions( _ ) :- !. generate_name_candidates_from_previous_substitutions( Unknown_name_as_string ) :- previous_name_substitution( Unknown_name_as_string, Substitution_as_string ), convert_underscored_string_to_list_of_words( Substitution_as_string, Substitution_as_list_of_words ), assertz( name_candidate( Substitution_as_list_of_words ) ), assertz( previously_used_name_substitution_found ), !. generate_name_candidates_from_previous_substitutions( _ ) :- !. generate_name_candidates_in_database( Lists_of_possible_words ) :- generate_one_name_candidate( Lists_of_possible_words, Word_list_of_a_name_candidate ), assertz( name_candidate( Word_list_of_a_name_candidate ) ), fail. generate_name_candidates_in_database( Lists_of_possible_words ). generate_one_name_candidate( [ List_of_first_words | Lists_of_subsequent_words ], [ First_word_in_name_candidate | Other_words_in_name_candidate ]) :- member( First_word_in_name_candidate, List_of_first_words ), generate_one_name_candidate( Lists_of_subsequent_words, Other_words_in_name_candidate ). generate_one_name_candidate( [], [] ). list_name_candidates_from_database( [ First_name_candidate | Rest_of_name_candidates ] ) :- name_candidate( List_of_words ), retract( name_candidate( List_of_words ) ), First_name_candidate = List_of_words, list_name_candidates_from_database( Rest_of_name_candidates ). list_name_candidates_from_database( [] ) :- !. write_list_of_name_candidates( [ First_list_of_words | Other_lists_of_words ] ) :- increment_counter( candidate_number ), read_counter( candidate_number, Candidate_number ), write( Candidate_number ), write( '. '), write_name_candidate( First_list_of_words ), nl, write_list_of_name_candidates( Other_lists_of_words ). write_list_of_name_candidates( [] ) :- nl, reset_counter( candidate_number ), !. test_deduce( Unknown_name_as_list_of_words, Name_substitution_as_list_of_words ) :- deduce_word_substitutions_from_given_name_substitution( Unknown_name_as_list_of_words, Name_substitution_as_list_of_words), !, word_substitution( Abbreviation, Word ), nl, write( Abbreviation), write( Word ), fail. deduce_word_substitutions_from_given_name_substitution( Unknown_name_as_list_of_possibly_uppercase_words, Name_substitution_as_list_of_possibly_uppercase_words ):- make_list_of_words_lowercase( Unknown_name_as_list_of_possibly_uppercase_words, Unknown_name_as_list_of_words ), make_list_of_words_lowercase( Name_substitution_as_list_of_possibly_uppercase_words, Name_substitution_as_list_of_words ), convert_list_of_words_to_list_of_characters( Unknown_name_as_list_of_words, Unknown_name_as_list_of_characters ), convert_list_of_words_to_list_of_characters( Name_substitution_as_list_of_words, Name_substitution_as_list_of_characters ), can_abbreviate_list1( Unknown_name_as_list_of_characters, Name_substitution_as_list_of_characters ), length( Name_substitution_as_list_of_words, Number_of_words_in_substitution ), ( ( Number_of_words_in_substitution =:= 5, nth1( 1, Name_substitution_as_list_of_words, First_word ), nth1( 2, Name_substitution_as_list_of_words, Second_word ), nth1( 3, Name_substitution_as_list_of_words, Third_word ), nth1( 4, Name_substitution_as_list_of_words, Fourth_word ), nth1( 5, Name_substitution_as_list_of_words, Fifth_word ), name( First_word, First_word_character_list ), name( Second_word, Second_word_character_list ), name( Third_word, Third_word_character_list ), name( Fourth_word, Fourth_word_character_list ), name( Fifth_word, Fifth_word_character_list ), /* It can be possible that some words in the name substitution have no abbreviated correspondent in the unknown name. For this reason, we must accept also empty lists in the appending process. */ append5( First_word_abbreviation, Second_word_abbreviation, Third_word_abbreviation, Fourth_word_abbreviation, Fifth_word_abbreviation, Unknown_name_as_list_of_characters ), can_abbreviate_list0( First_word_abbreviation, First_word_character_list ), can_abbreviate_list0( Second_word_abbreviation, Second_word_character_list ), can_abbreviate_list0( Third_word_abbreviation, Third_word_character_list ), can_abbreviate_list0( Fourth_word_abbreviation, Fourth_word_character_list ), can_abbreviate_list0( Fifth_word_abbreviation, Fifth_word_character_list ), append5( [ First_word_abbreviation ], [ Second_word_abbreviation ], [ Third_word_abbreviation ], [ Fourth_word_abbreviation ], [ Fifth_word_abbreviation ], All_abbreviations_as_list ), generate_potential_word_substitutions( All_abbreviations_as_list, Name_substitution_as_list_of_words ) ) ; ( Number_of_words_in_substitution =:= 4, nth1( 1, Name_substitution_as_list_of_words, First_word ), nth1( 2, Name_substitution_as_list_of_words, Second_word ), nth1( 3, Name_substitution_as_list_of_words, Third_word ), nth1( 4, Name_substitution_as_list_of_words, Fourth_word ), name( First_word, First_word_character_list ), name( Second_word, Second_word_character_list ), name( Third_word, Third_word_character_list ), name( Fourth_word, Fourth_word_character_list ), /* It can be possible that some words in the name substitution have no abbreviated correspondent in the unknown name. For this reason, we must accept also empty lists in the appending process. */ append4( First_word_abbreviation, Second_word_abbreviation, Third_word_abbreviation, Fourth_word_abbreviation, Unknown_name_as_list_of_characters ), can_abbreviate_list0( First_word_abbreviation, First_word_character_list ), can_abbreviate_list0( Second_word_abbreviation, Second_word_character_list ), can_abbreviate_list0( Third_word_abbreviation, Third_word_character_list ), can_abbreviate_list0( Fourth_word_abbreviation, Fourth_word_character_list ), append4( [ First_word_abbreviation ], [ Second_word_abbreviation ], [ Third_word_abbreviation ], [ Fourth_word_abbreviation ], All_abbreviations_as_list ), generate_potential_word_substitutions( All_abbreviations_as_list, Name_substitution_as_list_of_words ) ) ; ( Number_of_words_in_substitution =:= 3, nth1( 1, Name_substitution_as_list_of_words, First_word ), nth1( 2, Name_substitution_as_list_of_words, Second_word ), nth1( 3, Name_substitution_as_list_of_words, Third_word ), name( First_word, First_word_character_list ), name( Second_word, Second_word_character_list ), name( Third_word, Third_word_character_list ), /* It can be possible that some words in the name substitution have no uabbreviated correspondent in the unknown name. For this reason, we must accept also empty lists in the appending process. */ append3( First_word_abbreviation, Second_word_abbreviation, Third_word_abbreviation, Unknown_name_as_list_of_characters ), can_abbreviate_list0( First_word_abbreviation, First_word_character_list ), can_abbreviate_list0( Second_word_abbreviation, Second_word_character_list ), can_abbreviate_list0( Third_word_abbreviation, Third_word_character_list ), append3( [ First_word_abbreviation ], [ Second_word_abbreviation ], [ Third_word_abbreviation ], All_abbreviations_as_list ), generate_potential_word_substitutions( All_abbreviations_as_list, Name_substitution_as_list_of_words ) ) ; ( Number_of_words_in_substitution =:= 2, nth1( 1, Name_substitution_as_list_of_words, First_word ), nth1( 2, Name_substitution_as_list_of_words, Second_word ), name( First_word, First_word_character_list ), name( Second_word, Second_word_character_list ), /* It can be possible that some words in the name substitution have no uabbreviated correspondent in the unknown name. For this reason, we must accept also empty lists in the appending process. */ append( First_word_abbreviation, Second_word_abbreviation, Unknown_name_as_list_of_characters ), can_abbreviate_list0( First_word_abbreviation, First_word_character_list ), can_abbreviate_list0( Second_word_abbreviation, Second_word_character_list ), append( [ First_word_abbreviation ], [ Second_word_abbreviation ], All_abbreviations_as_list ), generate_potential_word_substitutions( All_abbreviations_as_list, Name_substitution_as_list_of_words ) ) ; ( Number_of_words_in_substitution =:= 1, nth1( 1, Name_substitution_as_list_of_words, First_word ), name( First_word, First_word_character_list ), can_abbreviate_list0( Unknown_name_as_list_of_characters, First_word_character_list ), generate_potential_word_substitutions( [ Unknown_name_as_list_of_characters ], Name_substitution_as_list_of_words ) ) ). deduce_word_substitutions_from_given_name_substitution( _, _). generate_potential_word_substitutions( [ First_word_abbreviation | Rest_of_word_abbreviations ], [ First_word | Rest_of_words ] ) :- First_word_abbreviation \== [], name( First_word_abbreviation_as_string, First_word_abbreviation ), /* For the time being we shall not exclude the possibility that the found word substitution would be also a usual abbreviation, because, since we give a high priority to the word substitutions in the deabbreviation process, we may be able to deabbreviate more effectively. It is namely so that a programmer is likely to use the same abbreviations (word substitutions) over and over. */ \+ dictionary_word( First_word_abbreviation_as_string), \+ domain_word( First_word_abbreviation_as_string ), \+ word_substitution( First_word_abbreviation_as_string, First_word ), \+ name_substitution( First_word_abbreviation_as_string, First_word, Any_list_of_line_numbers ), assertz( word_substitution( First_word_abbreviation_as_string,First_word)), /* In this phase we could also try to generate more potential word substitutions just by combining two adjoining word abbreviations and corresponding words. However, we leave this out for the time being. It is namely so that the deabbreviation mechanism, provided that it splits the unknown word into small pieces enough, should be able to redetect the two (or more) adjoining abbreviations again. */ generate_potential_word_substitutions( Rest_of_word_abbreviations, Rest_of_words ). generate_potential_word_substitutions( [ First_word_abbreviation | Rest_of_word_abbreviations ], [ First_word | Rest_of_words ] ) :- /* It comes here when the abbreviation was emply list or the substitution was already known. */ generate_potential_word_substitutions( Rest_of_word_abbreviations, Rest_of_words ). generate_potential_word_substitutions( [], [] ). write_all_name_substitutions :- name_substitution( Name_in_string_form, List_of_substitution_words, List_of_line_numbers ), write( Name_in_string_form ), write( ' ' ), write_name_candidate( List_of_substitution_words ), write( ' ' ), write( List_of_line_numbers ), nl, fail. write_all_name_substitutions.