-
Notifications
You must be signed in to change notification settings - Fork 3
/
DMNBase.gf
299 lines (259 loc) · 9.16 KB
/
DMNBase.gf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
incomplete concrete DMNBase of DMN =
WordnetNPsI
-- , Numeral
** open
Prelude,
Predef,
Coordination,
Syntax,
Sentence,
Extend,
Symbolic,
LexDMN,
DMNParams in {
lincat
-- Other lincats are {s : Str}, compiler inserts automatically
-- Rest defined in DMNParams
DTRow = DMNParams.Row ;
[DTRow] = ListRow ;
FCell = Cell ;
FCells = Cells ;
[FCell] = ListCell ;
[FEELexp] = ListExp ;
FEELexp = Exp ;
Bool,
DMNVal = Val ;
FBinOp = BinOp ;
oper
HEA : Type = {hdr, exp : NP ; adv : Adv} ;
ListHESA : Type = {hdr, exp : [NP] ; s : [S] ; adv : [Adv]} ;
Cells : Type = {
s : S ;
adv : Adv
} ;
Cell : Type = {
s : HEA ;
h : HeaderType ; -- for coordination
} ;
ListCell : Type = {
s : ListHESA ;
conjType : ConjType ; -- TODO: more fine-grained later
} ;
lin
-- Binary operations
Feq = binop "=" LexDMN.feq ;
Flt = binop "<" LexDMN.flt ;
Fgt = binop ">" LexDMN.fgt ;
Flte = binop "<=" LexDMN.flte ;
Fgte = binop ">=" LexDMN.fgte ;
-- Booleans
-- True = {s = "True" ; t = VTrue} ;
-- False = {s = "False" ; t = VFalse} ;
-- : DMNVal
VNOne = {s = "1" ; t = VNum Singular} ; -- for linguistic accuracy
-- : String -> DMNVal ;
VS str = str ** {t = VString} ;
-- : Float -> DMNVal ;
VN flt = flt ** {t = VNum Plural} ;
-- : Bool -> DMNVal ;
-- VB bool = bool ;
NoComment = ss "" ; -- : Comment
CommentString = parenss ; -- : String -> Comment
-- FEEL expressions
FAnything = { -- : FEELexp ;
s = \\_ => [] ;
t = EAnything
} ;
FNullary val = { -- : DMNVal -> FEELexp ;
s = \\_ => val.s ;
t = EValue val.t
} ;
FInRange,
FInRangeInt = \bg,end -> { -- : Float -> Float -> FEELexp ;
s = case brev of {
B3 => \\_ => bg.s ++ "-" ++ end.s ; -- postprocess or use BIND to remove spaces
_ => \\_ => between bg end} ; -- TODO: depend on headertype
t = ERange ;
} ;
FSection op val = { -- : FBinOp -> DNMVal -> FEELexp ;
s = \\h => -- TODO: depend on headertype
let opS : Tuple Str = op ! brev ! h
in opS.p1 ++ opS.p2 ++ val.s ; -- do we need discontinuity?
t = case val.t of {
VNum _ => EValue (VNum Plural) ; -- "one or more/fewer things"
_ => EValue val.t }
} ;
oper
between : SS -> SS -> Str = \a,b ->
let aNP : NP = symb a ;
bNP : NP = symb b ;
in (mkAdv between_Prep (mkNP and_Conj (mkListNP aNP bNP))).s ;
---------------------
-- List of FEELexp --
---------------------
lin
BaseFEELexp e1 e2 =
case <e1.t, e2.t> of {
-- If any subexpression is Anything, the whole expression is Anything.
<_,EAnything>|<EAnything,_> -- Replaced with just one FAnything later.
=> twoTable HeaderType e1 e2 ** {t = EAnything};
_ => twoTable HeaderType e1 e2 ** {t = EList}
} ;
ConsFEELexp e es = lin ListFEELexp (
case <e.t, es.t> of {
<_,EAnything>|<EAnything,_>
=> consTable HeaderType comma es e ** {t = EAnything} ;
_ => consTable HeaderType comma es e ** {t = EList}
}) ;
Disj es = case es.t of {
EAnything => FAnything ;
x => conjunctDistrTable HeaderType or_Conj es ** {t = x}
} ;
-- : CN -> FEELexp -> FCell ;
Attribute = -- Fallback: Header is FEELexp "Dish is Stew"
headerWhen HAttribute with_Prep ;
Event = header HAttribute upon_Prep ;
IsTrue = headerBool HTrue ;
IsFalse = headerBool HFalse ;
Location, -- {City,Paris} ~ "In Paris"
TimeSeason = -- {Month,May} ~ "In May"
header HLocation in_Prep ;
TimeClock = -- {Time,14:00} ~ "At 2 PM", "At any Time"
header HLocation at_Prep ;
AmountCount hdr1 hdr2 exp = -- {XCount,=<10} ~ "With 10 or fewer Xs"
headerCount HAmountCount for_Prep hdr1 hdr2 exp ;
-- Duration, -- {Weeks,[3..5]} ~ "Between 3 and 5 Weeks"
-- Weight, -- {XWeight,3 kg} ~ "X weighs 3 kg"
-- Length, -- {XLength,3 m} ~ "X is 3 m long"
-- Height, -- {XHeight,3 m} ~ "X is 3 m tall"
-- AmountMass, -- {CupsOfX,5} ~ "With 5 Cups of X". NB. the header needs to contain the unit and the material.
oper
headerWhen : HeaderType -> Prep -> CN -> FEELexp -> Cell =
\h,prep,hdrCN,expr ->
let cell : Cell = header h prep hdrCN expr in cell ** {
s = cell.s ** {
adv = mkAdv when_Subj (cell2s cell) }
} ;
header : HeaderType -> Prep -> CN -> FEELexp -> Cell =
\h,prep,hdrCN,expr -> {
s = case expr.t of {
EAnything
=> any prep hdrCN ;
_ => let expNP : NP = symbNP h expr in
{hdr = det expr hdrCN ;
exp = expNP ;
adv = mkAdv prep expNP} } ;
h = h
} ;
headerBool : HeaderType -> CN -> Cell = \h,hdrCN -> {
s = let expNP : NP = mass hdrCN in -- hdr is informative, exp is just T/F
{hdr = emptyNP ;
exp = expNP ;
adv = mkAdv when_Subj (mkS (mkCl (mkVP expNP)))} ;
h = h
} ;
headerCount : HeaderType -> Prep -> (number,apple : CN) -> FEELexp -> Cell =
\h,prep,nbr,guest,expr ->
let number_of_guests : CN = partCN nbr guest ;
five_to_eight : Det =
case expr.t of {
EList|ERange|EValue (VNum Plural)
=> aPl_Det ; -- Override for different langs
_ => a_Det } ** {s = expr.s ! h} ;
in {s = case expr.t of {
EAnything
=> any prep number_of_guests ;
_ => let expNP : NP = mkNP five_to_eight guest in
{hdr = emptyNP ; -- will use existential, no hdr
exp = expNP ; -- there are 5-8 guests
adv = mkAdv prep expNP }} ; -- with 5-8 guests
h = h ;
} ;
det : FEELexp -> CN -> NP = \expr ->
case expr.t of {
EList|ERange|EValue (VNum Plural)
=> thePl ;
_ => theSg } ;
any : Prep -> (header : CN) -> HEA = \upon,hdrCN ->
{hdr = mkNP hdrCN ; --nonExist ; -- In standard DMN, wildcard can't be output
exp = anything_NP ;
adv = Syntax.mkAdv upon (anyNP hdrCN)} ;
anyNP : CN -> NP = mkNP anySg_1_Det ;
symbNP : HeaderType -> Exp -> NP = \h,expr ->
Symbolic.symb (expr.s ! h) ;
partCN : CN -> CN -> CN = \number,apple ->
mkCN number (mkAdv part_Prep (mkNP aPl_Det apple)) ;
cell2s : Cell -> S = \c ->
case <c.h,brev> of {
<HFalse,_> => mkS negativePol (mkCl (mkVP c.s.exp)) ;
<_, B3> => np2s c.s.exp ;
<HTrue, _> => mkS (mkCl (mkVP c.s.exp)) ;
_ => mkS (mkCl c.s.hdr c.s.exp) -- Hdr is Exp
} ;
-------------------
-- List of cells --
-------------------
lin
BaseFCell c1 c2 = {
s = {hdr = mkListNP c1.s.hdr c2.s.hdr ;
exp = mkListNP c1.s.exp c2.s.exp ;
s = mkListS (cell2s c1) (cell2s c2) ;
adv = mkListAdv c1.s.adv c2.s.adv} ;
conjType = case eqHeaderType c1.h c2.h of {
True => UseConj ;
False => NoConj } ;
h = headerType c1.h c2.h ;
} ;
ConsFCell c cs =
case c.h of {
HAnything => cs ; -- don't add to list items that are Anything
_ => {s = {hdr = mkListNP c.s.hdr cs.s.hdr ;
exp = mkListNP c.s.exp cs.s.exp ;
s = mkListS (cell2s c) cs.s.s;
adv = mkListAdv c.s.adv cs.s.adv} ;
conjType = UseConj ; -- always use conj for longer lists than 2
h = headerType c.h cs.h}
} ;
-- : [FCell] -> FCells ;
Many cs =
let conj : Conj = case cs.conjType of {
UseConj => and_Conj ;
NoConj => and_Conj ** {s1,s2 = []} } ; -- Override for other langs
in {s = mkS and_Conj cs.s.s ;
adv = mkAdv conj cs.s.adv} ;
-- : FCell -> FCells ;
Single cell = {
s = cell2s cell ;
adv = cell.s.adv
} ;
------------------
-- List of rows --
------------------
-- : Int -> FCells -> FCells -> Comment -> DTRow ;
Row rownum inputs outputs comments =
let num : Str = table {B1 => "#" ++ BIND ++ rownum.s ; _ => []} ! brev ;
input : Adv = inputs.adv ;
output : S = outputs.s ;
inputOutput : S = Sentence.ExtAdvS input output ;
in {s = table {
ThenIf => num ++ (mkUtt output).s ++ (mkUtt input).s ++ comments.s ;
IfThen => num ++ (mkUtt inputOutput).s ++ comments.s }
} ;
BaseDTRow = twoTable Order ;
ConsDTRow = consrTable Order tablesep ; -- tablesep defined in each concrete
-- TODO aggregation, e.g.:
-- the dish is:
-- #1 Kidney bean stew in Winter
-- #2 Smoked tofu salad in Spring
-- #3 Roasted potatoes and a nice steak in Summer
-- #4 Instant noodles in Autumn for between 5 and 8 guests
-- #5 Pea soup in any season for any number of guests ( I give up )
-- : [DTRow] -> DTable ;
Table = conjTable order tablesep ;
-- This is for cases like
-- "(output) The contract is terminated, (input) when X, Y and Z."
-- "(input) When the contract is terminated, (output) the Company's obligations are A, B and C."
Consequence rows = {
s = rows.s2 ! ThenIf ++ tablesep ++ rows.s1 ! IfThen
} ;
}