1 kyu
Simple Interactive Interpreter
998 of 2,404Wintermute
Loading description...
Interpreters
Algorithms
View
This comment has been reported as {{ abuseKindText }}.
Show
This comment has been hidden. You can view it now .
This comment can not be viewed.
- |
- Reply
- Edit
- View Solution
- Expand 1 Reply Expand {{ comments?.length }} replies
- Collapse
- Spoiler
- Remove
- Remove comment & replies
- Report
{{ fetchSolutionsError }}
-
-
Your rendered github-flavored markdown will appear here.
-
Label this discussion...
-
No Label
Keep the comment unlabeled if none of the below applies.
-
Issue
Use the issue label when reporting problems with the kata.
Be sure to explain the problem clearly and include the steps to reproduce. -
Suggestion
Use the suggestion label if you have feedback on how this kata can be improved.
-
Question
Use the question label if you have questions and/or need help solving the kata.
Don't forget to mention the language you're using, and mark as having spoiler if you include your solution.
-
No Label
- Cancel
Commenting is not allowed on this discussion
You cannot view this solution
There is no solution to show
Please sign in or sign up to leave a comment.
Your C# "tokenize" method is a mess. For some unknown reason it adds closing parenthese ")" to the end of the input. Also, the regex is a complete mess too, it does not parse numbers at all and there are other issues with it.
Why even have such starting code if it is wrong?
How perform operations between numbers and functions
x * function x y
function x y * y
and function and function
functionA x y * functionB y x
Definetly a Tough Kata, but worth it. I learned a lot from this one :D
Looks like not all inputs are displayed in log for C#.
For example in "conflicts" tests i can see only:
But with
Console.WriteLine(input)
i can see:Also in "variables" tests in log i can see
input("y") == <> and not <25> => wrong solution, aborted!
But in previous "function" tests with
Console.WriteLine(input)
(not in default log) i can seeSo I thought there should be different scopes for different sections of the tests. If not, then the answer in "variables" tests should be
y = 25
This comment has been hidden.
The precedence of
=
is lower than that of+
. You should be parsinghijwpyk = 73 + 44
ashijwpyk = (73 + 44)
not as(hijwpyk = 73) + 44
.It looks like the error message has the "expected" and "received" backwards -- that is, your code said 73, but the expected value is 117.
How should the expression
5 + abc 2 + 5 3
, whereabc
is a function with two parameters, be evaluated? This expression is permissible by the grammar, however the language spec lists+
as a higher priority than functions. Intuitively, I'd want to just evaluate the function first, but that seems to go against what is explicitly stated, unless I'm misunderstanding how priority works.Edit: To anyone else wondering about how the priority properly works, function calls are the highest priority. Then, the operations in the table follow accordingly. Function assignment is the lowest priority.
Looking at this kata but haven't tried it yet. That said, the parser would know how many parameters the function needs when it sees its name. Thereby knowing how many expressions to parse to be able give it the parameters it needs. Keeping in mind that an expression would continue to parse as long as it possibly can and still being a valid expression. Thus the parser would parse two subsequent expressions (resolving "2 + 5" and "3" respectively) and give them to the function, evaluate it, and continue on.
It will not stop at just the "2", because "2 + 5" is a valid expression; it will however stop there, because "2 + 5 3" is not a valid expression (as per the grammar).
I hope that makes sense.
The error handling… This one was harder than expected, writing it while learning to type in Dvorak made it even harder :)
Please enable newer versions of Node for the JavaScript version of this kata, as it is in Simpler Interactive Interpreter. Coming from there and then having to rewrite larger parts of the existing code, because one used features that are not available in Node 8, is an unnecessary obstacle.
Not bad one. Can easy solve it after solve the 'Parsing and evaluation of mathematical expressions(c#)'.
Should have added test to check if function params are passed in right order
C translation added
I think a lot needs to be done in this kata, but overall it's good. I got a lot of satisfaction while solving that kata and 2 kyu Simple Interactive Interpreter. Wanna to solve something same
ENBF grammar is missing description of how tokens are separated by whitespace.
I think
fn add x y => x + z
should be valid because z could later be defined as a function, and the description doesn't define any scope limitations for functions.(Of course exceptions would be if
add
was already a variable, or ifx
ory
were already functions, but I don't think that's true for the test case)Another unclear point IMO; are functions allowed to define local variables, and if so, can it then read them? I don't see anything in the description disallowing this.
If this is allowed, it's another case where evaluating a function for validity before a function is executed more difficult.
Description has "the only variable names allowed in the function body are those declared by the arguments list"
Sure, but it doesn't say anything about the scope of function names, and we don't know when a function is declared if an unknown identifier will later be defined as a function. (and since the syntax for calling a function with no arguments is identical to the syntax for evaluating a variable, we can't tell from context either).
I think your point about the description does imply that variables may not be declared in function definitions, though my solution allows this and doesn't fail any validators.
As far as I can see, suggested syntax does not support such statements:
I had a good time while working on this kata, but realizing that you cannot do something more powerful because of the poor function call syntax saddens me a bit
I think so. It's grammar is ambigious.
Another example:
it supports, you just need to pass arguments like in haskell
Suppose
Since function calls are right associative, then how can we parse
apply incr 1
intoapply incr 1
but notapply (incr 1)
?After skimming the other discourses I found that this problem would very possibly not be tested ;)
I don't think the current syntax supports passing functions as arguments and calling them inside a function. 🤔
Hi. I'm surprised by these two test cases that seem to contradict each other:
fn x => 0
must raise an error according to the buttontest
,fn one => 1
must be a valid function with no arguments and always return 1 according to the attempt.In my opinion the first test case means 'a function must have a name' but in that case
x
could be considered to be the name of a function..Should the test case be modified? How did you managed this?
It takes one weeks for solving this problem. I've got alot of things about Rust.
I had fun solving this. It is not super hard if one already knows the classic technique. Supporting functions makes it indeed harder than the 2 kyu version. I'm only partially happy with my code, I think I could get rid of some redundancy with some good refactoring.
I dont understand this is note valid 'fn x => 0 x() = 0 and fn one = 1 is valid name of funciton = x x dont have any argument ı think this should be valid to
According to the spec, if a user declares a global variable 'x = 5', then a function 'fn x => 0', that function should be valid. Function parameter 'x' shadows a variable declared by the user. I can only guess why this is invalid. Maybe spec is wrong, or test case, or all function params must be used. I'll find out soon enough.
Hold on, the function name is 'x', while there is already a global variable named as such. An error is expected.
Currently input("avg 4 2 + avg 10 30") with output 13.0 is accepted, whereas you would like it to be 23.0 It's the difference between avg 4 (2+avg 10 30) = 13.0 and (avg 4 2) + (avg 10 30) = 23.0
I've added this as an extra feature to my program. The default is to interpret input("avg 4 2 + avg 10 30") as avg 4 (2+avg 10 30) whereas adding explicit brackets around the custom functions overrides the default so that input("(avg 4 2) + (avg 10 30)") outputs 23.0 in that case
Which one is required now?
4 (2+avg 10 30) = 13.0
or(avg 4 2) + (avg 10 30) = 23.0
? Thanks really.The first one.
4 (2+avg 10 30) = 13.0
This comment has been hidden.
Kotlin translation added :D
Not an issue.
Did you mean expression?
This comment has been hidden.
This will only start an escalating arms race. There will always be new ways to cheat. Just do not cheat, so $DEITY will not have to kill any baby seals.
Closing.
Please can help you learn how to solve the same problems at least approximately, I mean what topics you need to know ideally, or maybe some articles to read, that's how you got to this level(very important), please write!, here's my mail: zhenya.orlov86@mail.ru
This kata will be a lot harder if you start from scratch, but doing the easier kata in the description should give you a solid structure for this one. The most important topic you should know is how to evaluate a math expression. Hint: an expression of "1 + 2" is in the form called infix notation, you can transform it to other forms for easier parsing.
avg x y
. Seems like a basic use case and grammar allows it.avg echo 2 echo 5 echo 7
, but again no variables in sight. How aboutavg echo x echo 2 echo y
, it would require truly context-aware parsing that needs to distinguish vars from funcs and understand number of parameters, atm it's more or less easy to hack it throughThe original author is inactive. Any chance of getting some eyes on my CFML Translation? Thanks!
CFML Translation!
Having completed this in JavaScript, I noticed some of the tests enforced typing, meaning if my code returned "5" instead of 5, the test failed. The input is tokenized into all strings to start wtih and it didn't seem right to make any assumptions about types, nor did the instructions give any direction in the typing system of the language we were supposed to be implementing. Is this an oversight in the JS test cases to enforce numeric returns or a valid requirement that just wasn't explicitly stated in the dsecription?
Tests are apparently intended to expect
Number
s in all cases, except when the result should be an emptyString
or anError
. This is less than ideal ( expecting inconsistent return datatypes is not a best practice ), but IMO the description does a reasonable job of specifying it.All examples, and the note at the end, point to the value of an expression being a
Number
. This could have been specified explicitly, you could consider that an oversight, but I wouldn't really consider that a breaking issue. It's a reasonable default, and nowhere areString
s accepted where aNumber
should have been returned.Does that answer your question?
love the kata. There is so much in there to learn. Grammar transformations, applying Visitor pattern, ...
There are some ambiguities such as order of evaluation, e.g. "4 / 2 * 3" is 6.0 according to the kata, but could be 2/3 also, but these can be resolved through debug statements.
Usually mathematical expressions like this are calculated left to right so it would be 2 * 3 = 6
Yeah, thanks for mentioning it. It is just a convention though, as far as i know. As far as i know, it is not something mathematical. So i just like to have it explicit, because it is just a convention, right?
I do not believe the problem description uniquely specifies the result of the following:
This could either return 10 or 9, depending on whether it is evaluated as
(f 2 3) + 4
, orf 2 (3 + 4)
.Function calls should thus be added to the precedence table.
I haven't completed the kata, but I would take f 2 3 + 4 as (f 2 3) + 4, in the same manner that 23+5 is taken as (23)+5
Did you finish the kata? Which precedence order was correct?
It's probably implementation-dependent, and there do not seem to be tests with it currently.
I think I recall coming across this because I was failing some tests due to whichever order the tests expected. Maybe I just noticed it from the specification though. Unfortunately it was so long ago that I don't remember.
It is defined uniquely by the grammar; function calls have highest precedence.
No it is not. The production rule for function call is given as
That says, that the arguments of the call are
expression
s.3 + 4
is an expression, so interpreting the inputf 2 3 + 4
as equivalent tof 2 (3 + 4)
is valid according to the grammar. That the grammar listsfunction-call
(only) as an option forfactor
does not change that. The grammar is simply ambiguous. In more ways than this.It should be mentioned explicitly in the problem description that all calculations are to be made with floats, not integers.
It is reasonable to assume by default that "5 / 3 = 1", especially given that Ruby works in that manner.
Added a note in the "Language" section of the description.
The following test case should be added (or similar):
This will check that function composition is parsed correctly, i.e. above expression is parsed as
f2 (f2 1 2 3) (f1 4 5) (f1 6 7)
.Without that explicit test wrong programs will fail at random tests, leading to tedious and exhausting debugging.
Added in all languages.
Another weird Ruby issue:
My solution passes, but only if I evaluate the input string before calling my code (for example by printing it, or just by evaluating it without doing anything with the output). If I don't do that, tests 12 14 and 16 counting back from the end consistently fail. Weird, no?
After passing the first 318 tests I'm getting the following error in Ruby. It appears to be in the test code because my code is never actually called by the test that rasies this.
<NoMethodError: undefined method
to_postfix' for main:Object> main.rb:483:in
helper_3' main.rb:399:insolution' main.rb:629:in
block (3 levels) intimes' main.rb:626:in
block (2 levels) inwrap_error' /runner/frameworks/ruby/cw-2.rb:72:in
it' main.rb:514:inblock in <main>' /runner/frameworks/ruby/cw-2.rb:55:in
block in describe' /runner/frameworks/ruby/cw-2.rb:46:inmeasure' /runner/frameworks/ruby/cw-2.rb:51:in
describe' main.rb:513:in `Should be working now.
Thanks :)
May I be able to know on which test case I get all shown test cases PASSED(Passed: 27 Failed: 0 Exit Code: 1) but TIMEOUT? Am I allowed to know the input of the 28th test case?
Oh, boi. Got so far, user tests are passing. Then on the random tests I realize that my parser is right associative so 6/3/2 is 4 not 1.
ok that was actually quite easy to work around.
Clojure Translation. Please, review and approve.
Can function change arity after overwriting? I mean if I have > fn f a => a > fn g a b => a + b > fn F a b => f g a b then
F = f (g a b)
; but if I'll overwritef
andg
: > fn f a b => a + b > fn g a => a thenF
becomesF = f (g a) b
and that breaks AST tree forF
. When I started to code I thinked that if we have > fn f a => b and then we have > fn g a b => f a b on input we should return error, but now I'm not sure.Should I store functions as strings and recompile them at each call? In that case I'll need to accept almost any function as I cannot correctly detect another function calls in it and then return error only when function is used; or should I check function correctness when it's provided to me?
Or it means that I cannot call one function from another?
Solution that disallows function from function calling passes the test so you can assume it's disallowed to call one function from another
Wow that simplifies things. Is this still the case?
Feels extremely hard (and my solutions has lots of code), but definitely a nice challenge! Also nice how Rust works out here, I think it really shines here compared to e.g. C++/Javascript/Python/etc.
By the way: could the Rust version be updated? The newer Rust version is ergonomically much nicer!
Too much detail not show in desciption, the grammar shouldn be much clear, i really dislike the scope design and function call design ... but this kata is really great kata!
It's stated that function can access only the variables defines in it's arguments list. But what about a function calling other functions? Is it allowed?
C++ translation. Please, review and approve.
Ruby translation. Please, review and approve.
Should
x = 13 + y = 3 + 1
be allowed in the sense ofx = 13 + (y = 3 + 1)
? The grammar rules seem to allow it, but with the given precedence rules it would semantically not work as it would be interpreted asx = ((13 + y) = (3 + 1))
. It would work if=
has lower precedence over the other operators that occur to the right of it, but would have the highest precedence over all operators occurring to the left of it.The given expression can be broken down to
x = expr1
, whereexpr1: 13 + y = 3 + 1
due to the operator'='
's lower prescedence compare to'+'
. Again,expr1: expr2 = expr3
whereexpr2: 13 + y
,expr3: 3 + 1
. Bothexpr2
andexpr3
are valid expressions ify
is already assigned. However, even ifexpr2
could be resolved,expr1
would end up being an invalid expression, since'='
operator only takes an identifier on the left-hand side.tl;dr: the expression should cause an error.
Indeed, that confirms what I wrote earlier: "with the given precendence rules it would semantically not work". I was wondering if then the grammar rules should not be adapted to disallow this construct (or else, the precedence rules adapted to make them compatible with the grammar rules).
For Java, tests will not compile if you have input method throw an Exception.
Can get tests to compile by throwing Error, but then assertFail tests fail due to the error thrown.
You can try throwing
RuntimeException
.Nice kata, though missing some test cases that would make it super difficult. By the end my code was not the most elegant, and would probably fail some additional test cases.
Which error should I raise out when I'm using Python?..
anyone.
I am unclear about the function precedence: if the following input is received
> func 1 + 5
, is that taken to mean> (func 1) + 5
or> func (1 + 5)
The description of this kata doesn't specify the function call precedence. On the other hand, there aren't tests that depend on it. All tests can be successfully passed in both cases.
So, you can choose any of these options (or implement two versions of the interpreter :) )
C translation has been published.
Could anyone review and approve it, please?
This comment has been hidden.
False alarm - I had a bug in my code.
Please correct me if i am wrong but doesn't this
identifier ::= letter | '' { identifier-char } identifier-char ::= '' | letter | digit
mean that an identifier can only have one letter if it starts with a letter not an underscore, in the tests the function names (which are id identifiers) have names like 'avg' which would seem to violate this. I may have the wrong end of the stick here so please correct me if i'm wrong.
Except that in the current context, the
{...}
meansrepetitions
;)This comment has been hidden.
It's perfectly welcomed I think.
This comment has been hidden.
Great kata! Thanks for publishing it.
This comment has been hidden.
Fixed
Ruby-Translation kumited!
https://www.codewars.com/kumite/58e6ab740446a02a34000198?sel=58e6ab740446a02a34000198
Could you check and approve it, please?
Finally managed to find both the time and determination to complete this.
Hilariously enough, my solution is a fair bit shorter, and yet very descriptive and simple, then a few other solutions.
Not shorter than my solution;-)... Seems to me your solution is about 30 lines longer, but ok a little bit smaller, so at the end perhaps the same length, who knows:-)... But it's always the same - some solutions are better and some are weaker, often it depends on the problem (known or not) and the time you have or you want to invest for this single kata;-). For me the question always is, if you are able to solve many different problems and at codewars perhaps in short time (and sometimes different languages too):-)...? But good work:-)! By the way i think my "Tiny Three-Pass Compiler" code is not half length than your code;-)...
Of course, I only vaguely examined the first couple solutions presented to me, and all of them very significantly longer. Or maybe I simply missed your short solution amidst the walls of code.
Come to think of it, I appear to have implemented a two-pass compiler in my solution. Amusing to only notice it in retrospective.
When I click view either of your solutions, it says "There is no solution to show". Is that a bug? I'm curious as to how my code stacks up to 1dan code. Mine is only 74 lines if you remove the blank lines (96 otherwise, for readability). And somehow a few tabs slipped in there and messed up my indentation on my while statements, argh!
Seems the "no solution" message appears when the other person's submitted solution is in a different language than yours.
Extremely enjoyable kata. Thanks for taking the time to put this together with a clear problem statement and nice tests.
The non-terminal for 'number' is incorrect, as it allows for empty strings. The correct one should be (using 'T+' for '(T {T})' ) number := digit+ [ '.' digit+ ] | '.' digit+
I think there should be a test that uses the result of a funciton call as an operand. E.g.:
I can't get this test to pass for Python 3:
input: 'fn add x y => x + z'
This should raise an error, and when I test this by hand with this exact input, my code correctly raises the error about
z
not being recognized. All of my other tests pass. Advice? Is there a problem or quirk with this test?This comment has been hidden.
The description states:
So
fn add x y => x z
is an error, even ifz
is defined in the global scope.Does anyone know how I can remove this kata as 'completed' from my account? A friend completed it for funs sake and it doesn't reflect my level so would like it removed
you cannot do that.
What should be the outcome in such a case :
is it F1(x,F2(y+1)) or is it F1(x,F2(y))+1 ?
The grammer isn't clear about this.
it depends on F2's arity
@eugene -- how? in both the interpretations F2's arity is one.
@eugene, can you exapand? I'm wondering the same thing. cc @Wintermute
Hey, I'm coding in python and I don't really know what to return for an error. My code returns a few error messages now but I guess they aren't accepted. And I also saw Strikeskids post about this. Is there a problem with the kata or is it just me?
raise an Exception
Nice kata series. Looks like I've learned something new about regular expressions. Thanks.
The unit test definition seems to be out of date with the version of HSpec used:
The unit test definition seems to be out of date with the version of HSpec used:
python kata:
test.assert_equals(interpreter.input("avg avg 6 10 echo 2"), 5)
Should this case be tested?
What's wrong with it?
This comment has been hidden.
This comment has been hidden.
Wow, this was such a great challenge! While the description is very thorough, I do have one suggestions:
Once again, I really enjoyed this. Thanks a lot for taking the time to make this happen!
Great Kata! I really enjoyed this.
Very nice Kata with Compiling Theory. Deal with it using LL(n). And there are something about Operator Combination
a=(b=1)
/right or(6/3)*2
/left. Dynamic Function is very interesting. A function is a block/namespace + an expression. Eval a function is to eval an expression(There are no blocks). Parsing function/invoke:func-with-n-args arg1 arg2 ... argn
->func-with-n-args exp1 exp2 ... expn
So, wrote
Expr
class(AST), think about grammar(LL(n) recursion, need Compiling Theory) and start.There are no tests in the kata using invalid identifiers for variables and function names i.e.
Interpreter().input("3 = 4")
It is mean that identifier can include more than one char only if it starts with
_
. Is it mistake?Read it as
identifier ::= (letter | '_') { identifier-char }
Actually, ISO 14977 ENBF defines repetition to have a higher precedence than alternation, so indeed, it should be read as the original poster indicates. That's also how I coded my grammar.
Very nice and thorough description, but I think it should also specify the operator precedence with regards to function arguments. For example
I think, the logical thing would be for it to behave like this (see below), but a specific mention in the description might help avoiding ambiguity
Also, adding a few test cases about that might be very nice.
That was a really nice kata, had a lot of fun with it. And it took me more time than I thought it would. I will definitely have a look at some compiler theory - now I'm hooked.
I'm stuck with
functions(InterpreterTest)
test case.My code return
0.0
when a function is added (I didn't see in description what it should return).fn one => 1
looks fine for me so I return0.0
but I guess anException
is expected.conflicts
test case pass and there is almost the same situation E.g :fn f => 1
Can someone tell me why ? or what is expected ?
Ok,
null
is expected when a function is added.Nice Kata.
That was a real challenge. Took me over four hours to put it right. And I don't wanna read that code I wrote one more time. It's simply a mess... Perhaps I should've learned compiler theory at college.
Anyway, thanks for providing such interesting problems!
Great kata!
4nyN4m3Fun is a valid function name?
Thanks!
This was a fun kata! One suggestion is to include a list of error conditions you should check for and throw, since there were a few that I either missed in the problem description, or that weren't specified (for example, the requirement that the parameters to a function be uniquely named). Other than that, nice job!
This kata has a great description and set of tests. Good job :)
How should the state of
(x=3) + (x=2)
look after evaluation?{'x':2}
? Or just left as undefined behaviour as it is in C?Translated into Java.
Not an issue.
This comment has been hidden.
This comment has been hidden.
A top notch problem. Well defined, lucid with plenty of tests.
Helped improve my python.
Thanks.
I get the following error:
No matter what my program is. Even with preloaded solution, example test cases.
There is
});
missing at the end of line 24 of preloaded test cases.Already fixed
This comment has been hidden.
The arity of the function does need to be taken into account. Since only functions which have already been declared may be called, the intepreter has all of the information it needs to make that call.
As a more general example, take the following expression in Polish (prefix) notation:
A prefix interpreter knows that
+
is a binary operator, so it takes the1 2
as the arguments to+
, then*
takes the resulting3 2
, resulting in 6.Likewise, in your example the interpreter knows that
echo
is a unary function, so it takes only the first argument in the stack.Hope that helps. If there was any particular part of the description that led you to believe that arity wouldn't need to be taken into account, please let me know and I will try to clarify that section.
Thank you Wintermute, I was able to finish the Kata after your explanation. I believe that adding this information to the description will actually benefit future trainees. As a side note, I'd never use a language in practice that relies on arity for parsing and still rejects excess arguments like this :)
Very nice and well prepared Kata. Thanks!
I think the tests could cover few more corner cases, e.g. each of the following should probably be throwing errors
Hey, sorry for the late reply.
fn
should be an unambiguous identifier, and is not specifically reserved by the spec.fn
is not defined in the arguments list.Thanks for the feedback! If you would like to make a detailed case for 1 and/or 4, I'll gladly consider it.
fn
a keyword not an identifier, and you can't normally name your variables as keywords can you? Iffn
is accepted as variable or function name then things likefn + 1
andfn f
andfn f + 1
should also be accepted, but I suspect that might trip existing solutions. Either way a test or two would make it less ambiguous.fn f fn => fn + 1
-- should be an error again becausefn
is a keyword.Hello, awesome test.
The are 3 cases that failed on present solutions at the time I am writing this.
[expression, expected] ["9", 9] ["-9", -9] [ '-9/-3*4', 12 ]
I've added a test for "9", and it works correctly for my solutions in both JavaScript and Python. Note that numbers are defined as as a sequence of digits (with an optional decimal part), and no unary minus operator is defined. Your second two expressions are therefore not valid inputs.
You are right. Sorry for the inconvenience. I intuitively though about valid arithmetic operations
Is the javascript Function constructor disabled? it appears to work in the test cases but doesnt work when I submit the solution.
Yes, it is disabled. I'm not sure why it would be enabled when you're running your own tests. Sounds like a site bug to me.
I believe this has to do with the execution order of code blocks when you submit your solution. The way I see it, the order goes from Preloaded -> Your solution -> Kata's test fixture. It seems that your own test fixture gets its own environment, unaffected by the Preloaded code block.
There's an error in the pre-loaded test cases:
Should be:
Fixed. It would be really nice if example test cases were run against the reference solution during validation...
What's the precedence for function calls? You don't specify in the description.
E.g.
Should that calculate
5 + 2
first, use7
as the argument fortwice
, and return14
? Or should it performtwice 5
first, then add10 + 2
, resulting in12
?edit: I made my solution execute function calls last, along with
=
(and they both associate from right to left). Sotwice 5 + 2
would be14
. This is the most logical, since multi-argument functions would have to execute the function call last anyway - e.g.x = twice avg 2 + 3 5 + 6
, which should result inx
having the value16
.Your python test bench cases that check for an error are missing a string error message argument. This causes the test bench code to instantly fail when you try to test your code.
Interesting. Apparently the JavaScript and Python test frameworks are a bit inconsistent. Fixed now.
This comment has been hidden.
I enjoyed this kata very much. The only thing lacking in the description is which objects may be accessed from where:
The test cases can be passed by short-cutting many features of the language. Functions calling other functions don't need to be supported to pass the tests as well as functions without arguments. The simplest solution just would switch-case the finite number of test cases and return the appropriate result. My solution rejects ' ' as input, which seems unintended.
There should be at least one randomized test, preferably with functions having an unpredictable number of arguments and in unpredictable composition. Eventually, the interpreter should reject an input like '1 2', which is currently not tested. e.g. in my solution, parsing is done as far as possible and then the result is returned to the caller. The outer function must check that the whole input is read. If I left this check out, the result of evaluating '1 2' would be '1', but throwing an error makes more sense to me.
Yes. There is no seperate variable decleration syntax; variables are always created when they are first assigned.
No. Functions here are akin to mathematical functions. That is, a function operates solely on the specified inputs and produces exactly one output. This behavior is covered both by the kata description and the test cases.
I'm inclined to leave this as undefined behavior. My original solution does not support calling functions inside of another function's body, but I don't see the point in explicitly disallowing it either.
Functions calling other functions isn't part of the spec as discussed above. Not testing parameterless functions was an oversight, and I've added a couple tests to cover them.
If someone really wants to write a switch to cover every test case, they're more than welcome to do so. I'm not really interested in thwarting anyone that determined to ignore the spirit of the kata.
I dislike the unpredictableness of randomized tests. A random test is just as likely to allow a submission to pass as it is to generate a valid corner case. I would prefer to identify specific corner cases and add non-random tests for them. I agree that throwing an error is the correct behavior for the input '1 2', and I have added a test to that effect. I'm happy to add tests for other specific issues that you can come up with as well.
The problem with trying to allow functions calling other functions is, we've already decided that functions can't access global variables, and for any given name there can be either a variable or a function, not both (to avoid conflicts).
If I try to define this, it's supposed to give an error, because the variable
y
is not in the argument list:fn sum x => x + y
But if
sum
can call other functions,y
doesn't have to be a variable. It could be another function which doesn't require any arguments. And maybey
isn't defined yet. How is it supposed to know when you definesum
whether it's valid or not?Maybe you've defined a global function named
y
a while ago, but you still meant to define yoursum
function as this:fn sum x y => x + y
Since you forgot to put
y
in the argument list, is it going to use the globaly
function instead of giving you an error?Seems it's not possible to build AST for function calls at compile time. For examle expression "a b c" can be treated as "a(b, c)" or "a(b(c))". Of course at runtime we can parse such expressions, since defined variables and functions are known. So, what is the proper way to parse "a b c" expression?
Note the word "interpreter" in the kata title. There is no "compile time"; each statement is evaluated as it is entered. As such, the correct interpretation of the input
a b c
is dependent on the context of the preceding statments.It is possible if you do it on every line, since you can lookup the function arity of aleady parsed functions.
This kata is great. Hard enough to be really interesting, but not an overwhelming task. The tests are very well put together.
Minor issues:
In the tests for argument count it should say "too" instead of "to" in the message.
The tests for argument count don't have complete coverage. My solution passes the test, but I realized after I submitted it that it would fail if the test was of
>avg echo 1 echo 2 echo 4
rather than just having literal numbers as arguments.Thanks! I'm very pleased that you enjoyed it.
I've fixed the grammatical errors and added two additional tests that combine method chaining and invalid arg counts.