1

We have a relatively simple assignment that I understand in theory but I think I just don't quite understand Prolog's syntax enough to get that into code. Basically, we have a list of English notations that represent operations in C. They're stored as a list when they're passed to our Prolog program. For example:

add 4 to 3

is

[add, 4, to, 3]

We need to write a function that takes that list an returns the equivalent. So if I called

english2C([add,4,to,3], C).
C = 4+3

It would bind C to the result. So the data structure itself would be something like +(4(3)). We have a list of such English notation we have to translate, so it's a finite number. It's not like we have to account for all possibilities. There are also combinations, where they take two operations and combine them (with a comma in between)

english2C([add,3,to,5,',',then,subtract,7], C).
C = 3+5-7

I'm just somewhat confused as to how to start. I know I can take the very first element of the list and that will always be an operator (+,-,*, etc etc) and then I can just recursively go through the list looking for the operands. The problem there is for things that require order of operations, like "add 3 to 5 then multiply by 4", which should be represented as (3+5)*4 but if you just translate it directly you get 3+5*4.

Oh and we have to see if we can get it to run backwards (give it a C statement (3+5) and translate back to english (add 3 to 5)). That part I don't really have an idea for at all.

EDIT: There's a large enough permutations of possible English notations that I can't just pattern match everything. I get the idea that what I need to do is match the first operator with it's corresponding arithmetic symbol then find the operands. For a combinational statement, that would be the first part (so I would have 3+5) and then there would be a comma followed by the next statement. By the way, the combinational statements can be as long as they want, so it's not just two statements and I'm done.

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
user1777900
  • 975
  • 3
  • 13
  • 27

1 Answers1

2

If there is a reasonable small number of patterns, you could do:

english2C([add,X,to,Y], R) :- R is X+Y.
english2C([add,A,to,B,',',then,subtract,C], R) :- R is A+B-C.

edit

Those rules above compute the value. To translate, we can use DCG for matching, it's working 'backwards' as well.

english2C(In, R) :- phrase(toe(R), In, []).

toe(X+Y) --> [add,X,to,Y].
toe(X*Y) --> [multiply,X,by,Y].
toe(L-R) --> toe(L), [',',then,subtract,R].

test:

?- english2C(X,3+6).
X = [add, 3, to, 6].

edit sorry, I forgot a cut. With that added, I get

?- english2C([add,3,to,5,',',then,subtract,4],X).
X = 3+5-4.

?- english2C(L,3+5-4).
L = [add, 3, to, 5, ',', then, subtract, 4].

without, there is the loop after ;

?- english2C([add,3,to,5,',',then,subtract,4],X).
X = 3+5-4 ;
^CAction (h for help) ? goals
[698,875] toe(_G2096630, [add, 3, to, 5, ',', then, subtract, 4], _G2096652)
[698,874] toe('<garbage_collected>', '<garbage_collected>', _G2096652)
...

It's a single point change: do you prefer to find it yourself?

CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • Unfortunately it's not THAT small XD But the idea is right. Basically the idea I have is to match the first element with an operator then go down into the list to get the operands, but that would have to be recursive and I have to be able to separate the combinational statements. – user1777900 Nov 06 '12 at 18:58
  • Oh that's.....a lot simpler than what I was trying to do. And it works more reliably as well. Thanks a bunch. – user1777900 Nov 08 '12 at 01:41
  • 1
    Oh, almost anyways. I have to tweak it a bit since it works for all cases where there is a rule defined, but if I use some random phrase that isn't defined in the rules (it should return no) there's a stack overflow error. But other than that, I think it works. – user1777900 Nov 08 '12 at 02:08
  • Oh, I see what it is. There are two times it crashes. If it gives me an answer and I don't accept it (type ';') it tries to redo the call but the answer from the previous call (3+5) is already stored and it goes into an infinite loop. But I don't think I can add a cut to stop it. Likewise if it doesn't find the phrase in the lists of rules, it goes into an infinite loop. There should be a way to just return no though. – user1777900 Nov 08 '12 at 02:16
  • Attempt to keep the code simpler than possible, mimic the syntax as far as you can. This could be a rather 'void' hint, because reducing the program to more essential terms can be difficult or impossible... – CapelliC Nov 08 '12 at 02:19
  • It seems it's just the implementation of phrase that causes this. When you attempted a phrase such as [add,3,to,5,',',then,subtract,4] it overflows because it first finds 3+5 and then goes into an infinite loop trying to get to the -4 part. I'll probably just have to figure out a way to implement it purely as a list of rules. – user1777900 Nov 08 '12 at 02:38
  • Oh man, ok lemme see if I can find it. I've been trying to put a cut somewhere to stop it from going into an infinite loop. The main problem is that I thought you couldn't put cuts when you were writing DCG rules. Is the cut somewhere else then? – user1777900 Nov 08 '12 at 03:10
  • Ok, sorry that I've been so much trouble. That problem seems to be solved by putting toe(L-R) --> toe(L), !, [',',then,subtract,R]. But what about if the user tries to put a phrase that doesn't exist in th ruleset? For example, they try [2, plus, 2], but such a rule isn't defined. Normally, prolog just returns 'no' to indicate that it wasn't found, but it seems like it goes into an infinite loop here. I don't think a cut will work here, since it never finds an answer to begin with (where as the other worked since the answer was found we just had to stop it there) – user1777900 Nov 08 '12 at 03:28
  • So in the end, while this was a lot of help and I think I can figure this out using DCGs, I don't think I can use phrase specifically because the way that toe(E) is called recursively, if I put cuts to stop the infinite looping, I can't combine more than two terms. For example, we need to be able to do [add,3,to,5,','then,subtract,4,',',then,subtract,1], basically we need to be able to append as many base rules together as we want. But when I try to move the cut to allow that, it looks like that causes an infinite loop in the above mentioned case. – user1777900 Nov 08 '12 at 04:13