Actualy it is not hard. Basic tokenization an lexical analysis. What makes it tricky is baned code. It should be mentioned that you can't use built-in ast or generic visitor. Also can't use dataclasses even i use 3.8. Other than this, nice one.

and you're right, I was aware from the beginning that unary minus has highest precedence, but assigned it to a wrong function and it failed to parse, then assigned it to different wrong function again and it worked for all tests except the last two

I can't use munch because we use different packages, in your solution it's Text.ParserCombinators.ReadP from base and in my solution it's Text.ParserCombinators.Parsec from parsec, but it's amazing how similar they are ðŸ™‚

Kudos for doing the analysis. My hat is off to you. I've read it, though I haven't checked every intermediate result.

Am I correct that the reference solution implements the specs correctly, given the presence of negative numbers and unary minus, and -(a*b) not necessarily being the same as (-a*b) ( mutatis mutandis ) ?

These points ( negative numbers and -(a*b) vs. (-a*b) ) are not explicitly specified in the description ( unary minus gets too much attention actually; there is no reason to forbid a space after a unary minus but not anything else ), and I think it might be useful ( and honest ) to have them in there. So no, I don't think you should mark your comment as a spoiler, and given that not many people might read it, the description may even need to be updated.

Unary minus is not explicitly assigned a precedence, but I think it makes sense that unary minus comes before multiplication and division ( and after parentheses - everything comes after parentheses ).

And your solution now passes all tests? Ah, yes, I can see it now. Nice one! ( I like munch better than many though - it's [ sometimes much ] more efficient, see Hackage:munch ).

ETA: we have much the same solution. mine is here. that is used as the reference one too.

here we observe the interesting propery twice: > calc "-2.64* 99.59" "(- (2.64 * 99.59))" > calc "-( 27.88 ) * -45.71" "(- (27.88 * (- 45.71)))"

but the order is still correct, now the tricky part is evaluating them together: > calc (a ++ "-" ++ b ++ "/" ++ c) == ("(" ++ calc a ++ " - (" ++ calc b ++ " / " ++ calc c ++ "))") True

part = a ++ "-" ++ b ++ "/" ++ c ++ "-" ++ d > calc part == ("((" ++ calc a ++ " - (" ++ calc b ++ " / " ++ calc c ++ ")) - " ++ calc d ++ ")") False

I know exactly why that happens even if mathematically what I specified on the right is correct, now let's observe: > calc part "((((((((- 77.74) - (- 49.83)) - (((87.1 * 95.77) * 60.89) / ((19.4 / 48.03) / ((9.36 * 60.54) * (- (54.34 / 88.69)))))) - (30.12 * 16.51)) + 76.58) + ((7.33 * 37.22) * 32.52)) - 71.16) + (66.99 / 34.22))"

it simplifies to: u = ((((((a - (b / c)) - (30.12 * 16.51)) + 76.58) + ((7.33 * 37.22) * 32.52)) - 71.16) + (66.99 / 34.22))

now let's remove the duplicate from previous part to make it easier to see: v = (((((((u - (99.3 / 59.18)) + 47.01) - (- (2.64 * 99.59))) + 40.75) + (48.83 * 65.14)) + 11.3) + (89.38 * (- 5.43)))

so, I do have a correct left-to-right order, if I evaluated it differently the result would be 4.436349535535873e8 instead of 4.436588275515455e8 which is pretty close to expected 4.4365882755154556e8

arbitrary is far from how the ranking works

kata ranks are decided by users who have completed the kata in the beta phase. it can't be edited after being approved

also note that different languages share kata kyus.

I agree. The kata ranking on this website seems to be quite arbitrary.

When I try to run the program, I get the exact answer that it says it was expecting, but I'm still failing the test.

This comment is hidden because it contains spoiler information about the solution

freak

If ast is not allowed, you should state it on the description

how

Actualy it is not hard. Basic tokenization an lexical analysis. What makes it tricky is baned code. It should be mentioned that you can't use built-in ast or generic visitor. Also can't use dataclasses even i use 3.8. Other than this, nice one.

yes, your solution is correct ðŸ˜€

and you're right, I was aware from the beginning that unary minus has highest precedence, but assigned it to a wrong function and it failed to parse, then assigned it to different wrong function again and it worked for all tests except the last two

I can't use

`munch`

because we use different packages, in your solution it's`Text.ParserCombinators.ReadP`

from`base`

and in my solution it's`Text.ParserCombinators.Parsec`

from`parsec`

, but it's amazing how similar they are ðŸ™‚Kudos for doing the analysis. My hat is off to you. I've read it, though I haven't checked every intermediate result.

Am I correct that the reference solution implements the specs correctly, given the presence of negative numbers and unary minus, and

`-(a*b)`

not necessarily being the same as`(-a*b)`

( mutatis mutandis ) ?These points ( negative numbers and

`-(a*b)`

vs.`(-a*b)`

) are not explicitly specified in the description ( unary minus getstoo muchattention actually; there is no reason to forbid a space after a unary minus but not anything else ), and I think it might be useful ( and honest ) to have them in there. So no, Idon'tthink you should mark your comment as a spoiler, and given that not many people might read it, the description may even need to be updated.Unary minus is not explicitly assigned a precedence, but I think it makes sense that unary minus comes before multiplication and division ( and after parentheses -

everythingcomes after parentheses ).And your solution now passes all tests? Ah, yes, I can see it now. Nice one! ( I like

`munch`

better than`many`

though - it's [ sometimes much ] more efficient, see Hackage:munch ).ETA: we have much the same solution. mine is here. that is used as the reference one too.

ok, I patched the line responsible for unary minus and now I get expected results ðŸ˜Œ

maybe I should mark my comment above as a spoiler? ðŸ˜€

TLDR: I have a correct left-to-right order, but the cause of mismatch is the way my solution handles unary minus

let's carefully analyze the expression, first it needs to be cleaned up with

`unwords . words`

:`"-77.74 - -49.83 -( 87.1 * ( 95.77 ) ) * 60.89 /( 19.4 /( 48.03 ) /( 9.36 * 60.54 * -54.34 /( 88.69 ) ) ) - ( 30.12* 16.51 ) +76.58 + 7.33 * ( 37.22 )* 32.52- ( 71.16 ) + 66.99 /( 34.22 )- 99.3 /(59.18 )+ 47.01 - -2.64* 99.59 + 40.75 + 48.83 * 65.14 + 11.3 + 89.38 * -5.43 + ( 6.75 - ( 32.38- -----( 27.88 ) * -45.71+40.16 + 21.69 ) * 80.87 * 74.01 )"`

I need to break this into variables:

`a = "-77.74 - -49.83 "`

`b = "( 87.1 * ( 95.77 ) ) * 60.89 "`

`c = "( 19.4 /( 48.03 ) /( 9.36 * 60.54 * -54.34 /( 88.69 ) ) ) "`

`d = " ( 30.12* 16.51 ) +76.58 + 7.33 * ( 37.22 )* 32.52- ( 71.16 ) + 66.99 /( 34.22 )"`

`e = " 99.3 /(59.18 )+ 47.01 - -2.64* 99.59 + 40.75 + 48.83 * 65.14 + 11.3 + 89.38 * -5.43 "`

`f = " ( 6.75 - ( 32.38- -----( 27.88 ) * -45.71+40.16 + 21.69 ) * 80.87 * 74.01 )"`

so the expression is:

`entire = a ++ "-" ++ b ++ "/" ++ c ++ "-" ++ d ++ "-" ++ e ++ "+" ++ f`

let's evaluate those variables one at a time:

`> calc a`

`"((- 77.74) - (- 49.83))"`

`> calc b`

`"((87.1 * 95.77) * 60.89)"`

`> calc c`

`"((19.4 / 48.03) / ((9.36 * 60.54) * (- (54.34 / 88.69))))"`

`> calc d`

`"(((((30.12 * 16.51) + 76.58) + ((7.33 * 37.22) * 32.52)) - 71.16) + (66.99 / 34.22))"`

`> calc e`

`"(((((((99.3 / 59.18) + 47.01) - (- (2.64 * 99.59))) + 40.75) + (48.83 * 65.14)) + 11.3) + (89.38 * (- 5.43)))"`

`> calc f`

`"(6.75 - (((((32.38 - (- (- (- (- (- (27.88 * (- 45.71)))))))) + 40.16) + 21.69) * 80.87) * 74.01))"`

here we observe the interesting propery twice:

`> calc "-2.64* 99.59"`

`"(- (2.64 * 99.59))"`

`> calc "-( 27.88 ) * -45.71"`

`"(- (27.88 * (- 45.71)))"`

but the order is still correct, now the tricky part is evaluating them together:

`> calc (a ++ "-" ++ b ++ "/" ++ c) == ("(" ++ calc a ++ " - (" ++ calc b ++ " / " ++ calc c ++ "))")`

`True`

`part = a ++ "-" ++ b ++ "/" ++ c ++ "-" ++ d`

`> calc part == ("((" ++ calc a ++ " - (" ++ calc b ++ " / " ++ calc c ++ ")) - " ++ calc d ++ ")")`

`False`

I know exactly why that happens even if mathematically what I specified on the right is correct, now let's observe:

`> calc part`

`"((((((((- 77.74) - (- 49.83)) - (((87.1 * 95.77) * 60.89) / ((19.4 / 48.03) / ((9.36 * 60.54) * (- (54.34 / 88.69)))))) - (30.12 * 16.51)) + 76.58) + ((7.33 * 37.22) * 32.52)) - 71.16) + (66.99 / 34.22))"`

it simplifies to:

`u = ((((((a - (b / c)) - (30.12 * 16.51)) + 76.58) + ((7.33 * 37.22) * 32.52)) - 71.16) + (66.99 / 34.22))`

we still correctly get expressions evaluated left-to-right, let's move on:

`> calc (part ++ "-" ++ e)`

`"(((((((((((((((- 77.74) - (- 49.83)) - (((87.1 * 95.77) * 60.89) / ((19.4 / 48.03) / ((9.36 * 60.54) * (- (54.34 / 88.69)))))) - (30.12 * 16.51)) + 76.58) + ((7.33 * 37.22) * 32.52)) - 71.16) + (66.99 / 34.22)) - (99.3 / 59.18)) + 47.01) - (- (2.64 * 99.59))) + 40.75) + (48.83 * 65.14)) + 11.3) + (89.38 * (- 5.43)))"`

we get more parantheses on the left, it's ok:

`(((((((((((((a - (b / c)) - (30.12 * 16.51)) + 76.58) + ((7.33 * 37.22) * 32.52)) - 71.16) + (66.99 / 34.22)) - (99.3 / 59.18)) + 47.01) - (- (2.64 * 99.59))) + 40.75) + (48.83 * 65.14)) + 11.3) + (89.38 * (- 5.43)))`

now let's remove the duplicate from previous part to make it easier to see:

`v = (((((((u - (99.3 / 59.18)) + 47.01) - (- (2.64 * 99.59))) + 40.75) + (48.83 * 65.14)) + 11.3) + (89.38 * (- 5.43)))`

again it's correctly evaluated left-to-right, now let's get the final result:

`> calc entire`

`"((((((((((((((((- 77.74) - (- 49.83)) - (((87.1 * 95.77) * 60.89) / ((19.4 / 48.03) / ((9.36 * 60.54) * (- (54.34 / 88.69)))))) - (30.12 * 16.51)) + 76.58) + ((7.33 * 37.22) * 32.52)) - 71.16) + (66.99 / 34.22)) - (99.3 / 59.18)) + 47.01) - (- (2.64 * 99.59))) + 40.75) + (48.83 * 65.14)) + 11.3) + (89.38 * (- 5.43))) + (6.75 - (((((32.38 - (- (- (- (- (- (27.88 * (- 45.71)))))))) + 40.16) + 21.69) * 80.87) * 74.01)))"`

don't be scared, simplify and deduplicate from previous result again:

`(v + (6.75 - (((((32.38 - (- (- (- (- (- (27.88 * (- 45.71)))))))) + 40.16) + 21.69) * 80.87) * 74.01)))`

and fortunately:

`> calc entire == ("(" ++ calc (part ++ "-" ++ e) ++ " + " ++ calc f ++ ")")`

`True`

so, I do have a correct left-to-right order, if I evaluated it differently the result would be

`4.436349535535873e8`

instead of`4.436588275515455e8`

which is pretty close to expected`4.4365882755154556e8`

Yeah, it's too long for me as well.

I can't fix the random tests, unless you can show that the reference solution uses wrong order somewhere.

for reference here's the failed test:

`Falsifiable (after 33 tests): " -77.74\t- -49.83\t\n-(\n87.1\t*\t(\t95.77 )\t) \n*\t\n60.89 /(\n\t19.4\t/(\n48.03 ) /(\t\t9.36 *\n60.54\t*\n-54.34\t/( 88.69\t)\n\n\n\t) ) -\t \n ( \n30.12* 16.51 \t)\n+76.58 +\t7.33\t*\n(\n37.22\t)*\t32.52- \t(\n71.16 )\t+\t\t 66.99\t/( 34.22\t)-\n\n 99.3\n/(59.18 )+\n47.01\t- \t-2.64*\n99.59\n+\n40.75\n\t\t+\n48.83\n\t * 65.14 \t+ \n11.3\t+\n89.38\t\t\n\n\t\t*\n-5.43\t\n + (\n 6.75\t- (\n32.38-\n-----(\t27.88 )\n\n\n\n*\n-45.71+40.16 \t+\t21.69\n \n\t)\n* \n80.87 *\n74.01\t\t ) " expected 4.4365882755154556e8 but got 4.436588275515455e8`

and this is how my solution treats it:

`"((((((((((((((((- 77.74) - (- 49.83)) - (((87.1 * 95.77) * 60.89) / ((19.4 / 48.03) / ((9.36 * 60.54) * (- (54.34 / 88.69)))))) - (30.12 * 16.51)) + 76.58) + ((7.33 * 37.22) * 32.52)) - 71.16) + (66.99 / 34.22)) - (99.3 / 59.18)) + 47.01) - (- (2.64 * 99.59))) + 40.75) + (48.83 * 65.14)) + 11.3) + (89.38 * (- 5.43))) + (6.75 - (((((32.38 - (- (- (- (- (- (27.88 * (- 45.71)))))))) + 40.16) + 21.69) * 80.87) * 74.01)))"`

because the input is too long it's hard for me to spot where exactly it evaluates in wrong order

using

`foldl1`

instead doesn't change the result because it's used simply for a lookup table:## Loading more items...