I’ve been stuck on this for a few days. I’m writing a simple evaluator for the Forth exercise on Exercism.
My progress can be found here.
For the life of me I can’t seem to figure out how to pass the “can use different words with the same name” test and the test after understandably infinitely loops. I know my approach is wrong within the assignCommand function but I can’t think of how to force the value out of the pair and then use the new value as part of the new definition.
I’ve tried creating a temp variable/environment and trying to run the name first to see I can get the value in a new env and then redefining the name in the new environment but those don’t work.
Or maybe I need a new function which checks to see if the Text supplied to mkState is an existing member of the environment and forces it to use old values…but for now I’m out of ideas.
I believe choosing Map to implement the dictionary may set you up for tricky problems.
A number of Forth implementations have the dictionary as a linked list where each entry (word) is:
a pointer to the previous word
some flags + name length + the name itself
the definition
So the trick that is made possible by this implementation is that redefinition of old words are not replacements, but additions.
Let me illustrate with the test:
it "can use different words with the same name" $
runTexts [ ": foo 5 ;"
, ": bar foo ;"
, ": foo 6 ;"
, "bar foo" ] `shouldBe` Right [5, 6]
The ASCII diagram of the test dictionary would be:
NIL <-- foo <-- bar <-- foo
| | |
V V V
5 foo 6
Notice that foo was added twice. This representation is far from efficient but allows you to pass the test easily: bar fetches the fooat the time of definition; foo just fetches the last defined value, in a LIFO fashion.
I’ve been reading and rereading this all day and I think I have a strategy to implement this and it makes sense now, so I’ll try when I’m back from work later .
Thank you.
Regarding a more efficient implementation: could you briefly describe an overall strategy there as nothing is immediately coming to mind other than maybe having some form of stateful Map and the values coming from different states of the Map before returning a final state with the update one?