:- use_module(library(lists)). %%%********************** Type Hierarchy bot sub [list, sign, cat, index, head, sentence, person, gender, number, case, def, preposition_type, tense, yes_no]. yes_no sub [yes, no]. yes sub []. no sub []. list sub [e_list, ne_list, list_sign]. e_list sub []. ne_list sub [ne_list_sign] intro [hd:bot, tl:list]. % specialized list of signs list_sign sub [e_list, ne_list_sign]. ne_list_sign sub [] intro [hd:sign, tl:list_sign]. sign sub [word, phrase] intro [phon:list, cat:cat]. word sub []. phrase sub []. % if we want to filter incomplete phrases, we use this type and the % appropriate rule. % ---------------------- %sentence sub [] % intro [phon2: list]. cat sub [] intro [head:head, subcat:list, optcat:list]. index sub [] intro [person: person, gender: gender, number: number]. head sub [agr_base, preposition, marker]. agr_base sub [verb, nominal] intro [index:index]. verb sub [] intro [subject:sign, tense:tense]. tense sub [past, present, future]. % no "tzivuy" now past sub []. present sub []. future sub []. nominal sub [noun, adjective] intro [def: def]. noun sub [] intro [case: case, is_pron: yes_no]. adjective sub []. preposition sub [] intro [type: preposition_type]. marker sub [acc_marker, def_marker]. acc_marker sub []. def_marker sub []. person sub [first, second, third]. first sub []. second sub []. third sub []. gender sub [masc, fem]. fem sub []. masc sub []. number sub [singular, plural]. singular sub []. plural sub []. case sub [nom, acc]. nom sub []. acc sub []. def sub [definite, indefinite]. definite sub []. indefinite sub []. preposition_type sub [el,al,le,be,mi,shel,she]. % all possible types of prepositions. el sub []. al sub []. le sub []. be sub []. mi sub []. shel sub []. she sub []. %%%********************** Lexical Entries % ******************************************* % * Define simple parts of speech. % ******************************************* % * % * I'm using a transcript of the "lo-menukad" hebrew % * transcript. I had to use only English characters, % * so they will be recognized as prolog atoms. % * Nontrivial conversions are marked with an asterisk. % * % * Aleph - A, Teth - I*, Pe - P % * Bet - B, Yod - Y, Tsadi - C* % * Gimel - G, Kaf - K, Qoph - Q % * Dalet - D, Lamed - L, Reish - R % * He - H, Mem - M, Shin - V* % * Waw - W, Num - N, Tav - T % * Zayn - Z, Samekh - S, % * Xeth - X, 'Ain - E*, % ******************************************** :-lex_rule_depth(5). % ******************************************* % ******************************************* % ** % ** Nouns % ** % ******************************************* % ******************************************* % plain nouns. % they have person, number, gender case and definiteness % also it has a preposition (if any) so we remember that this % noun phrase can be converted to a preposition phrase. % currenly we allow only one preposition per noun, but there % is no real limitation to provide more. all_n_feats(Phon, Gen, Num, Def, Case) macro cat:(subcat:[], optcat:[cat:head:(adjective, def:(Def, Def2), index:(Index))], head:(noun,case:Case,def:(Def, Def2), is_pron: no, index:(Index,(number:Num, person:third, gender:Gen)))), phon:[a_ Phon]. simple_n(Phon, Gender) macro @ all_n_feats(Phon, Gender, singular, indefinite, _). prop_n_feats(Phon, Gen, Num) macro cat:(subcat:[], optcat:[cat:head:(adjective, def:definite, index:(Index))], head:(def:definite, case:nom, is_pron: no, index:(Index,(number:Num, person:third, gender:Gen)))), phon:[a_ Phon]. prop(Phon, Gender) macro @ prop_n_feats(Phon, Gender, singular). dgl ---> @ simple_n(dgl, masc). spr ---> @ simple_n(spr, masc). dbr ---> @ simple_n(dbr, masc). dlt ---> @ simple_n(dlt, fem). dnh ---> @ prop(dnh, fem). abyb ---> @ prop(abyb, masc). pronoun_feats(Phon, Gen, Num, Pers) macro cat:(subcat:[], optcat:[], head:(def:definite, case:nom, is_pron: yes, index:(number:Num, person:Pers, gender:Gen))), phon:[a_ Phon]. any ---> @ pronoun_feats(any, gender, singular, first). ath ---> @ pronoun_feats(ath, masc, singular, second). at ---> @ pronoun_feats(at, fem, singular, second). hwa ---> @ pronoun_feats(hwa, masc, singular, third). hya ---> @ pronoun_feats(hya, fem, singular, third). anxnw ---> @ pronoun_feats(anxnw, gender, plural, first). atm ---> @ pronoun_feats(atm, masc, plural, second). atn ---> @ pronoun_feats(atn, fem, plural, second). hm ---> @ pronoun_feats(hm, masc, plural, third). hn ---> @ pronoun_feats(hn, fem, plural, third). pronoun_acc_feats(Phon, Gen, Num, Pers) macro cat:(subcat:[], optcat:[], head:(def:definite, case:acc, is_pron: yes, index:(number:Num, person:Pers, gender:Gen))), phon:[a_ Phon]. awty ---> @ pronoun_acc_feats(awty, gender, singular, first). awtk ---> @ pronoun_acc_feats(awtk, gender, singular, second). awtw ---> @ pronoun_acc_feats(awtw, masc, singular, third). awth ---> @ pronoun_acc_feats(awth, fem, singular, third). awtnw ---> @ pronoun_acc_feats(awtnw, gender, plural, first). atkm ---> @ pronoun_acc_feats(atkm, masc, plural, second). atkn ---> @ pronoun_acc_feats(atkn, fem, plural, second). awtm ---> @ pronoun_acc_feats(awtm, masc, plural, third). awtn ---> @ pronoun_acc_feats(awtn, fem, plural, third). % lexical rules % some lexical entries may be created twice, or more. % we try to avoid this situation by imposing a certain order % in which lexical entries are created. first we deal with % the real morphological phenomena (singular/plural, male/female), % then add the definite article if necessary and then the prepositions. % one benefit is that we don't apply all lexical rules to proper nouns, % but the necessary ones. plural_masc_n lex_rule @ all_n_feats(_Phon1, masc, singular, indefinite, _) **> @ all_n_feats(Phon2, masc, plural, indefinite, _) morphs (X) becomes (X,ym) when chars_to_atom([X,ym],Phon2). plural_fem_n lex_rule @ all_n_feats(_Phon1, fem, singular, indefinite, _) **> @ all_n_feats(Phon2, fem, plural, indefinite, _) morphs (X,h) becomes (X,[w,t]) when chars_to_atom([X,w,t],Phon2), (X) becomes (X,[w,t]) when chars_to_atom([X,w,t],Phon2). % ******************************************* % ******************************************* % ** % ** Adjectives % ** % ******************************************* % ******************************************* all_adj_feat(Phon, Gender, Num, Def) macro cat:(subcat:[], optcat:[], head:(adjective, def:Def, index:(number:Num, person:third, gender:Gender))), phon:[a_ Phon]. % ****************************** % * Create female adjectives. % ****************************** make_female_adj lex_rule @all_adj_feat(_Phon1, masc, singular, indefinite) **> @all_adj_feat(Phon2, fem, singular, indefinite) morphs (X,[y]) becomes (X,[yt]) when chars_to_atom([X,yt], Phon2), (X) becomes (X,[h]) when chars_to_atom([X,h], Phon2). % ****************************** % * Create plural masculine adjectives. % ****************************** make_plural_masc_adj lex_rule @all_adj_feat(_Phon1, masc, singular, indefinite) **> @all_adj_feat(Phon2, masc, plural, indefinite) morphs (X) becomes (X,[y,m]) when chars_to_atom([X,ym], Phon2). % ****************************** % * Create plural feminine adjectives. % ****************************** make_plural_fem_adj lex_rule @all_adj_feat(_Phon1, masc, singular, indefinite) **> @all_adj_feat(Phon2, fem, plural, indefinite) morphs (X) becomes (X,[w,t]) when chars_to_atom([X,wt], Phon2). kxwl ---> @all_adj_feat(kxwl, masc, singular, indefinite). gdwl ---> @all_adj_feat(gdwl, masc, singular, indefinite). % ******************************************* % ******************************************* % ** % ** Accusative case marker % ** % ******************************************* % ******************************************* at ---> cat:(subcat:[], optcat:[], head:(acc_marker)), phon:[a_ at]. % ******************************************* % ******************************************* % ** % ** The definite article. % ** % ******************************************* % ******************************************* h ---> cat:(subcat:[], optcat:[], head:(def_marker)), phon:[a_ h]. %% JJ is the implied and invisible definite article that %% appears in phrases like "lspr" that can be read as "le sefer" %% where the book is indefinite or "la sefer" where the book is definite. jj ---> cat:(subcat:[], optcat:[], head:(def_marker)), phon:[]. % ******************************************* % ******************************************* % ** % ** Prepositions. % ** % ******************************************* % ******************************************* % ********************************************* % * Preposition rules. % ********************************************* pp(Phon, PrefType) macro word, phon:[a_ Phon], cat:(head:(preposition, type: PrefType), optcat:[], subcat:[(cat:head:(is_pron:no, case:nom))]). saturate_pp(Phon, PrefType) macro word, phon:[a_ Phon], cat:(head:(preposition, type: PrefType), optcat:[], subcat:[]). al ---> @pp(al, al). % with the opposite pronouncing :) el ---> @pp(el, el). vl ---> @pp(vl, shel). l ---> @pp(l, le). b ---> @pp(b, be). m ---> @pp(m, mi). % a try to insert "mishpat zika thru a "she" preposition that requires a % sentance (saturated vp) as a subcat v ---> word, phon:[a_ v], cat:(head:(preposition, type: she), optcat:[], subcat:[(cat:head:(verb),cat:subcat:[])]). % create special forms of prepositions make_more_prepositions lex_rule @ pp(Phon, PrefType) **> @ saturate_pp(Phon2, PrefType) morphs Phon becomes Phon2 when add_prep_suffix(Phon, Phon2). % just check the lexical entry. add_prep_suffix(b, Phon2) :- member(Phon2, [by, bk, bw, bh, bnw, bkm, bkn, bhm, bhn]). add_prep_suffix(l, Phon2) :- member(Phon2, [ly, lk, lw, lh, lnw, lkm, lkn, lhm, lhn]). add_prep_suffix(m, Phon2) :- member(Phon2, [mmny, mmk, mmnw, mmnh, maytnw, mkm, mkn, mhm, mhn]). add_prep_suffix(al, Phon2) :- member(Phon2, [alyy, alyk, alyw, alyh, alynw, alykm, alykn, alyhm, alyhn]). add_prep_suffix(el, Phon2) :- member(Phon2, [elyy, elyk, elyw, elyh, elynw, elykm, elykn, elyhm, elyhn]). add_prep_suffix(vl, Phon2) :- member(Phon2, [vly, vlk, vlw, vlh, vlnw, vlkm, vlkn, vlhm, vlhn]). % ******************************************* % ******************************************* % ** % ** Verbs. % ** % ******************************************* % ******************************************* % I use only verbs of the first and second "binyan", % to simplfy lexical processing (their past form only requiers suffixes). % % verbs that require a "musa yashir" and "musa akif" % such as "lakah sefer mi-shlomi". create_prep_element(Type) macro cat:head:(preposition, type:Type). create_acc_element macro cat:head:(noun, case:acc). verb_general(Phon, SubcatList, OptcatList) macro cat:(subcat:[(Subj ,cat:head:(noun, case:nom, index:Index))| % the subject SubcatList], % the objects optcat:OptcatList, % optinal PP head:(verb, subject:Subj, tense:past, index:(Index, number:singular, gender:masc, person:third))), phon:[a_ Phon]. lqx ---> @verb_general(lqx, [@create_acc_element], [@create_prep_element(mi)]). bxr ---> @verb_general(bxr, [@create_acc_element], []). hlk ---> @verb_general(hlk, [], [@create_prep_element((le ; al))]). emd ---> @verb_general(emd, [], [@create_prep_element(el)]). amr ---> @verb_general(amr, [(@create_acc_element;@create_prep_element(she))], [@create_prep_element(le)]). % the subject must come first. lex_verb_props(Phon, Number, Gender, Person, Subcat, Optcat) macro cat:(subcat:[(Subj ,cat:head:(noun, case:nom, index:Index))| % the subject Subcat], % the object optcat:Optcat, % optinal PP head:(verb, subject:Subj, index:(Index, number:Number, gender:Gender, person:Person))), phon:[a_ Phon]. make_verb_past_tense lex_rule @ lex_verb_props(Phon1, singular, masc, third, Subcat, Optcat) **> @ lex_verb_props(Phon2, Num, Gen, Pers, Subcat, Optcat) if instantiate_vars(Num, Gen, Pers) morphs X becomes (X,Suff) when verbs_past_suffix(Num, Gen, Pers, Suff, Phon1, Phon2). % need to instatiate the vars before using "deref" on them instantiate_vars(Num, Gen, Pers) if member(Num, [singular, plural]), member(Pers, [first, second, third]), member(Gen, [masc, fem, gender]). % find the appropriate suffix for this verb form (also create the correct phon). verbs_past_suffix(AleNum, AleGen, AlePers, Suffix, OrigPhon, NewPhon) :- deref(AleNum, _, PrologNum), deref(AleGen, _, PrologGen), deref(AlePers, _, PrologPers), check_verb_suffix(PrologNum, PrologGen, PrologPers, Suffix), chars_to_atom([OrigPhon, Suffix], NewPhon). % some entries specify "gender", so we won't have duplicate entries % for singular second person (bahart, baharta) check_verb_suffix(singular, gender, first, ty). check_verb_suffix(singular, gender, second, t). check_verb_suffix(singular, fem, third, h). check_verb_suffix(plural, gender, first, nw). check_verb_suffix(plural, fem, second, tn). check_verb_suffix(plural, masc, second, tm). check_verb_suffix(plural, gender, third, w). % % ******************************************* % ******************************************* % ** % ** Grammar Rules. % ** % ******************************************* % ******************************************* %last_rule rule %(Mother, sentence, phon2:Phon2) %===> %cat> (HeadDtr, phon:Phon2, cat:head:verb, cat:subcat:[]). %goal> phon_print_principle(HeadDtr). % ******************************************* % * % * The main schema (head-complement-adjunct), % * aka "all in one" scheme. % * % ******************************************* % some of the comps are in subcat, some are in optcat. % for documentation see the main documentation file (in hebrew). all_in_one rule (Mother, cat:subcat:[], cat:optcat:[]) ===> goal> (five_or_less(LeftDtrs), check_left_order(HeadDtr, LeftDtrs)), cats> (LeftDtrs), cat> HeadDtr, goal> head_feature_principle(Mother, HeadDtr), goal> (five_or_less(RightDtrs), check_right_order(HeadDtr, RightDtrs)), cats> (RightDtrs), goal> (append(LeftDtrs, RightDtrs, AllDtrs), total_comps_non_zero(AllDtrs), split_list(LeftDtrs, LeftComps, LeftAdjs), split_list(RightDtrs, RightComps, RightAdjs), check_empty_comps_subcats(AllDtrs), left_right_subcat_principle(LeftComps, HeadDtr, RightComps, Mother), left_right_adjunct_principle(LeftAdjs, HeadDtr, RightAdjs, _), list_phon_principle(LeftDtrs,HeadDtr,RightDtrs,Mother)). % ******************************************* % * Instantiate the "cats>" list and limit it. % ******************************************* five_or_less([]) if true. five_or_less([_]) if true. five_or_less([_,_]) if true. five_or_less([_,_,_]) if true. five_or_less([_,_,_,_]) if true. five_or_less([_,_,_,_,_]) if true. % ******************************************* % * The total number of complements & adjuncts % * is not zero. % ******************************************* total_comps_non_zero([]) if !,fail. total_comps_non_zero(_) if true. % ******************************************* % * Subcat Principle. % * See dodumentation. % ******************************************* left_right_subcat_principle(LeftComps, (HeadDtr, cat:subcat:HeadSubcat), RightComps, cat:subcat:MotherSubcat) if append(LeftComps, RightComps, AllComps), check_permutation(HeadDtr, HeadSubcat, PermutedHeadSubcat), append(MotherSubcat, AllComps, PermutedHeadSubcat). % ******************************************* % * If free order enabled, return permutation % * Otherwise return the same list. % * (checks the head of the rule). % ******************************************* check_permutation(Head, OrigComps, PermutedComps) if comps_ordered(Head), !, append(OrigComps, [], PermutedComps). check_permutation(_Head, OrigComps, PermutedComps) if !, permutation(OrigComps, PermutedComps). % ******************************************* % * Adjunct Principle. % * See documentation. % ******************************************* % assume the mother has an empty optcat left_right_adjunct_principle(LeftAdjs, (_HeadDtr, cat:optcat:HeadOptcat), RightAdjs, cat:optcat:MotherOptcat) if append(LeftAdjs, RightAdjs, AllAdjs), % check_permutation(HeadDtr, HeadOptcat, PermutedHeadOptcat), permutation(HeadOptcat, PermutedHeadOptcat), split_list(PermutedHeadOptcat, AllAdjs, MotherOptcat). % ******************************************* % * Ensure all subcats of the complements and % * adjuncts are empty. % ******************************************* check_empty_comps_subcats([]) if true. check_empty_comps_subcats([cat:subcat:[]|Rest]) if check_empty_comps_subcats(Rest). % ******************************************* % * Phonetic principles. See documentation. % ******************************************* list_phon_principle(LeftComps,Head,RightComps,Mother) if append(LeftComps, [Head], Tmp1), append(Tmp1, RightComps, AllDtrs), append_all_phon(AllDtrs, Mother). append_all_phon([], phon:[]) if true. append_all_phon([phon:First|Rest], phon:MotherPhon) if append_all_phon(Rest, phon:RestPhon), append(First, RestPhon, MotherPhon). % we could say that some verbs do not require a subject. % however its preferred that we will have a "hidden" subject. % ******************************************* % * % * The verb-no-subject scheme % * See documentation. % * % ******************************************* verb_no_subj rule (Mother) ===> cat> (HeadDtr, cat:head:(verb, tense:past)), goal> (head_feature_principle(Mother, HeadDtr), left_right_subcat_principle([(cat:head:(noun, is_pron:yes, case:nom, index:(person:(first;second))), phon:[])], HeadDtr, [], Mother), left_right_adjunct_principle([], HeadDtr, [], Mother), list_phon_principle([], HeadDtr, [], Mother)). % ************************************************* % * Make the noun phrase definite, % * This in fact may be considered a lexical rule, % * but we treat it as grammar rule in order to reduce % * the lexicon. % ************************************************* make_definite rule (Mother) ===> cat> (Marker, cat:head:def_marker), cat> (HeadDtr, cat:head:nominal), goal> (definite_principle(Mother, HeadDtr), special_phon_principle(Mother, Marker, HeadDtr)). % for definite nouns definite_principle(@ all_n_feats(_Phon1, Gen, Num, definite, nom), @ all_n_feats(_Phon2, Gen, Num, indefinite, _)) if true. % for definite adjectives definite_principle(@ all_adj_feat(_Phon1, Gen, Num, definite), @ all_adj_feat(_Phon2, Gen, Num, indefinite)) if true. % ************************************************* % * Make nouns accusative. % ************************************************* accusative_marker_rule rule (Mother, cat:head:(noun, def:Def, index:Index, case:acc), cat:optcat:[]) % make it accusative ===> cat> (Marker, cat:head:acc_marker), cat> (HeadDtr, cat:head:(noun, def:(Def,definite), index:(Index, person:third), is_pron:no, case: nom), cat:subcat:[]), % reduce possible derivations. goal> (left_right_subcat_principle([], HeadDtr, [], Mother), % left_right_adjunct_principle([], HeadDtr, [], Mother), list_phon_principle([Marker], HeadDtr, [], Mother)). % right order principle check_right_order(cat:head:(noun;verb;preposition), _) if true. check_right_order(_, []) if true. % left order principle check_left_order(cat:head:verb, _) if true. check_left_order(_, []) if true. % whether we can select any complement, or we need to follow the order. comps_ordered(cat:head:verb) if !, fail. comps_ordered(_X) if true. % phon_principle % ******************************************************* % this principle concatenates the phonetic sequence % for this sentence. % ******************************************************* % this version of the principle combines back the prefixes. % it will work only if the prefixes are combined back immediately. % it will work on "le dana" but not on "le dana hagdola". % (I require empty comp's subcat when applying rules, so % there is only one hirarchial way to do it. special_phon_principle(phon:[a_ MotherPhon], phon:[a_ LeftPhon], phon:[a_ RightPhon]) if prolog(isCharPrefix(LeftPhon)), !, prolog(atom_concat(LeftPhon, RightPhon, MotherPhon)). special_phon_principle(phon:MotherPhon,phon:Left,phon:Right) if append(Left,Right,MotherPhon). phon_print_principle(phon:List) if print_phon_list(List), prolog(nl). % ******************************************* % * The Head - Feature Principle. % ******************************************* head_feature_principle(cat:head:X, cat:head:X) if true. % ******************************************************* % * ALE implementations of some prolog functions. % ******************************************************* % ******************************************************* % * Append. % ******************************************************* append([],Xs,Xs) if true. append([H|T1],L2,[H|T2]) if append(T1,L2,T2). % ******************************************************* % * Member. % ******************************************************* member(X, hd:X) if true. member(X, tl:Xs) if member(X,Xs). % ******************************************************* % * Select. % ******************************************************* select(X,(hd:X,tl:Xs),Xs) if true. select(Member,(hd:X,tl:Xs),(hd:X,tl:Rest)) if select(Member,Xs,Rest). % ******************************************************* % * Permutation. % ******************************************************* permutation([], []) if true. permutation(List, [First|Perm]) if select(First, List, Rest), permutation(Rest, Perm). % ******************************************************* % * SplitList. (Advanced SubList). % ******************************************************* % split_list(CompleteList, List1, List2) % check whether merging List1 and List2 will produce CompleteList, % preserving the order. after this operation we have % sublist(List1, CompleteList) and sublist(List2, CompleteList), and % List1 and List2 have no common elements. split_list([], [], []) if true. split_list([Head|RestOfCompleteList], [Head|RestOfList1], List2) if split_list(RestOfCompleteList, RestOfList1, List2). split_list([Head|RestOfCompleteList], List1, [Head|RestOfList2]) if split_list(RestOfCompleteList, List1, RestOfList2). %% %% %% Utils. %% %% % ************************************** % convert an atoms list to a codes list. % ************************************** % A special case is the empty list, since it is an atom atoms_codelist([],[]) :- !. % If it is an atom (and not an empty list - []), % convert it using the "name" function. atoms_codelist(Word,Codes) :- atom(Word), name(Word,Codes). % If it is a list of atoms, convert it using the % the "charlist_to_codelist" function. atoms_codelist([Word|Words],Codes) :- charlist_to_codelist([Word|Words],Codes). % *************************************************** % * convert a list of characters into a list of codes. % * if the list contains lists of characters, it will % * flatten them into a single list. % *************************************************** % and empty list is converted to an empty list of codes. charlist_to_codelist([], []). % if it is a non empty list, we convert the first element % to a list of characters with the "atoms_codelist" function, % recursively process the rest of the list and then concatenate % the results. charlist_to_codelist([Word|Words],AllCodes) :- atoms_codelist(Word,Codes1), charlist_to_codelist(Words, Codes2), append(Codes1, Codes2, AllCodes). % ************************************************ % * Convert a list of characters into an atom. % * If sicstus prolog would follow the ISO standard % * it would be much easier. However we need to % * convert the list of characters into a list of % * ASCII codes, and then convert the list of codes % * into an atom. % * If the list contains sub-lists of characters, they % * are flatten. % * Also, the elements of the list may be atoms, % * and not necessarily single characters. % ************************************************ atomize_char_list(ListOfChars, Atom) :- charlist_to_codelist(ListOfChars, ListOfCodes), name(Atom, ListOfCodes). chars_to_atom(ListOfChars, Phon) :- atomize_char_list(ListOfChars, Phon), write('Created: '), write(Phon), write(' '), heb_write(Phon), nl. % convert & print an atom supplied in the transcript in a real hebrew. % (works on windows only). heb_write(Txt) :- name(Txt,List), print_heb_list(List). print_heb_list([]). print_heb_list([X|Rest]) :- print_heb_char(X), print_heb_list(Rest). print_heb_char(CharNum) :- name(Char, [CharNum]), nth0(N,[a,b,g,d,h,w,z,x,i,y,kk,k,l,mm,m,nn,n,s,e,pp,p,cc,c,q,r,v,t], Char), X is N + 224, name(HebChar, [X]), write(HebChar). % print list of words in the transcript. print_phon_list([]) if true. print_phon_list([a_ El1 | Rest]) if prolog(heb_write(El1)), prolog(write(' ')), print_phon_list(Rest). % ************************************************* % * split single char functions: % ************************************************* % the first argument is the word to be splitted. (in) % the second argument is the prefix splitted (out). % the third argument is the rest of the word. (out). % we need to leave something ..... split_one_char(_, [_Char], []) :- fail. % split a single character. split_one_char(Word, [Char], Rest) :- nonvar(Word), name(Word, [FirstChar|[RestChars1|RestChars2]]), name(Char, [FirstChar]), isCharPrefix(Char), name(Rest, [RestChars1|RestChars2]). % split a word into all possible characters. % first option - don't split - just check that the word exists split_word_all_prefixes(Word, [], Word) :- lex(Word,_Tag,_SVs,_IqsIn), !. % if multiple lexical entries exist, % it will cause multiple tries to parse % a phrase. % second option - do split. % the remainder must not be a prefix itself (there are no one-character) % words in hebrew. split_word_all_prefixes(Word, Prefixes, Rest) :- split_one_char(Word, [FirstChar], FirstCharRest), check_definite_jj(FirstChar, JJList), split_word_all_prefixes(FirstCharRest, NewPrefixes, Rest), check_no_h_after_preposition(FirstChar, NewPrefixes), \+ isCharPrefix(Rest), lex(Rest,_Tag,_SVs,_IqsIn), append([FirstChar|JJList], NewPrefixes, Prefixes). % the common prefixes. % when we encounter the "l" prefix we put into the stream both % the [l] and the [l,jj] atoms, so the "definite uncertainity" is resolved. % this way is quite ugly, but the two other alternatives are % to create separate lexical entries for each prefix (see hebrew-pref.pl), % or to create this uncertainity at the noun level. % Since the problem is only with the "b,l,k" prefixes, I don't want to % make the grammar more problematic. % the "jj" is just a lexical entry that does not have a phonetic % representation. besides, it has the same features as "h" isCharPrefix(X) :- member(X, [b,l,m,h,w,k,v]). % check whether a (phonetically) invisible definite article should be % inserted into the words string. % if the splitted character is a member of the list (be & le prefixes), % than the "jj" invisible definite article is inserted. % The use of this prefix can make problems while using generation, since some % nouns may suddenly become definite, while they shouldn't. check_definite_jj(Char, [jj]) :- member(Char, [b,l,k]). % otherwise no article is inserted. check_definite_jj(_Char, []). check_no_h_after_preposition(_FirstChar, []). check_no_h_after_preposition(FirstChar, [_Prefix1|_RestOfPrefixes]) :- \+ member(FirstChar, [b,l,k]). check_no_h_after_preposition(FirstChar, [RestPrefix1|_RestPrefixes]) :- member(FirstChar, [b,l,k]), \+ member(RestPrefix1, [h]). % lspr - > lasefer % split as [l,h,spr]. % lhspr -> *lehasefer % * split as [l,h,spr]. split_phrase_prefixes([], []). split_phrase_prefixes(ListOfWords, SplittedList) :- ListOfWords = [FirstWord|Rest], split_word_all_prefixes(FirstWord, Prefixes, FirstWordRest), split_phrase_prefixes(Rest, RestSplittedList), append(Prefixes, [FirstWordRest], Tmp1), append(Tmp1, RestSplittedList, SplittedList). rec2(List) :- split_phrase_prefixes(List, SplittedList), rec(SplittedList). rec3(List) :- rec(List,X,Y,Z), write(X),nl,write(Y),nl,write(Z),nl.