Beta

Makeshift pattern matching

Description
Loading description...
Algorithms
Fundamentals
Functional Programming
Recursion
  • Please sign in or sign up to leave a comment.
  • wthit56 Avatar

    It seems some of the tests have patterns that are simple objects, with set "matches" methods. Presumably we're meant to just call whatever the object's "matches" method is--regardless of where it has come from. I think that's how I'm doing it, but it wasn't clear to be from the description that how it must work.

    It's explicitly saying you must set such methods on the prototypes. But that's not even necessary if you're just calling the method on the value you're given. So again, just a bit muddled with the potential of overlooking or misreading it.

  • wthit56 Avatar

    I was given this by the randomised tests:

    assert.strictEqual(patternMatch(
      [ [], [ [Array], {}, [Object] ], [ [Array], [Object], [Array] ] ],
      [ [], [Array], [Array] ], true
    ), true);
    

    But I think it's incorrect. The pattern is expecting an array of 3 items:

    • First item is an array of 0 items.
    • Second item is an array of 1 item, an array (doesn't matter what it contains).
    • Third item is an array of 1 item, containing an array (doesn't matter what it contains).

    The input is an array containing 3 items:

    • First item is an array of 0 items. [Pass]
    • Second item is an array containing 3 items. [Fail]

    ...Right?

  • wthit56 Avatar

    This comment has been hidden.

  • wthit56 Avatar

    I don't know if you test for objects with { valueOf } or { toString } that make them look like other objects, but that could be a good test.

  • wthit56 Avatar

    This comment has been hidden.

  • wthit56 Avatar

    There are no sample tests for null or undefined that I got. Not strictly necessary--but to have such full coverage in the sample tests, but not quite all the basic ones seems like an oversight.

  • wthit56 Avatar

    "Properties do not need to be defined on the input for a match to succeed." Does that mean it has to be set on the input, but the value can be undefined? Can you have pattern={a:String}, input={} and that's fine? What about pattern={a:String}, input={a:undefined}? Not clear how this works, to me.

  • wthit56 Avatar

    The first Function sample test is telling me "(Number)[matchesSymbol] should be a function." It is a function. So... 🤷

    Also, I don't know why it's checking here.

  • wthit56 Avatar

    How to compare Sets is not specified. I passed the sample tests just by checking .\_\_name. That can't be all, surely?

  • wthit56 Avatar

    How to compare a Symbol to a Symbol isn't specified.

  • wthit56 Avatar

    Just reading the description, there's a number of ambiguities or confusing parts that I'd suggest need adjusting:

    • The whole [matchesSymbol] thing is just a bit odd to me. A simple method would work perfectly well, and would no longer require Symbol use and understanding--which is not what this kata is about.
    • "Why [matchesSymbol]? Using matchesSymbol enables custom pattern-matching behavior for user-defined types." Well... it doesn't; we have to implement it. Having a simple method would work exactly the same way.
    • "If we have the following class...then the following code will work." Again, no it won't, because we have to implement that. There's nothing inherent to using a Symbol for this that means this works, when not using a Symbol would mean it wouldn't work. It's just a choice you made for some reason.
    • You could even just leave this whole thing out and let the user implement it however they wish to. Just tell them what the main patternMatch() function needs to do, and let them do it however they wish. That would be exactly the same amount of challenge, they can choose if they want to split code across the prototypes or not, etc.
    • If you keep the prototype method idea, you could give a clear list of prototypes to implement the method for instead of leaving it to the user to figure out. That doesn't add to the challenge, it's just not explicitly defined in an easy to read manner.
    • "A function matches if: ..." Doesn't say if both conditions must be true, or at least one of them must be true. Seems like both must be true, as a guess. But then most functions would naturally not pass it. For example function(n) { return n > 10; } would make sense to match values over 10; that would be a common way of using such a patternMatch() function. But no number uses that function's prototype, so it will never pass the first condition. I recommen making it explicit if one or both are required for a function to match on a value.
    • "An array matches if...[all] elements match their corresponding element in the input" Unclear what is meant by "match" here. I expected it would just compare with a === or something. As you say later: "A pattern not covered by the above rules matches if it is considered equal to the input. The equality check should be a strict equality check." But maybe you literally mean, run the pattern matching algorithm between each item in the two arrays? To resolve this, maybe define "match" at the top. Like, "Value a matches value b, if a.matches(b) is truthy." Perhaps the issue is, you started by talking about patterns matching values. But further down you're talking about values matching values, and also sometimes "pattern matching" is just "===". So it all just gets a touch messy while reading and trying to understand. Something like this could help clear things up for people on first-read.
    • "{ nonExistent: undefined } matches {}" It's not clear which is the "pattern" and which is the "input" in that text.
    • Unclear why I would need that _() function instead of just returning true. I guess maybe some sort of "functional" thing, or monads, or whatever... but if the user wants to write the code that way, they'll know how to write const _ = () => true;. Not a big deal, just felt superfluous to me.

    All that said, I'm looking forward to trying out this kata now! Just wanted to get those thoughts out there while it was fresh.

  • Voile Avatar

    Stringify function is incorrect for Set: it stringifies Set instances as Set([]) instead of new Set([]), so the stringified value will always throw an error. Other primitive wrappers correctly contains new.

  • Voile Avatar

    Needs additional fixed test cases for matching falsy values with {}:

    testXMatchesY({}, NaN);
    testXMatchesY({}, false);
    testXMatchesY({}, 0);
    testXMatchesY({}, '');
    
    testXDoesNotMatchY({}, null);
    testXDoesNotMatchY({}, undefined);
    

    Also needs more tests for Sets:

    testXDoesNotMatchY(new Set([]), {});
    testXDoesNotMatchY(new Set([]), []);
    testXDoesNotMatchY(new Set([]), '1');
    testXDoesNotMatchY(new Set([]), 1);
    
  • JohanWiltink Avatar

    Why go to all this trouble when you can just write

    switch ( true ) {
      case /[a-z]/i.test(input): return "letter";
    }
    

    ?

  • JohanWiltink Avatar

    null matches null and nothing else.

    Is this a test on the pattern or on the input?

    Ie, can I skip ( almost ) all pattern matching after a pattern of null, or on an input of null ?

  • JohanWiltink Avatar

    [a] pattern matches if pattern[matchesSymbol](input) is truthy

    Is pattern[matchesSymbol] actually an invisible property of the pattern argument that will be passed to the solution function by testing? This is not clear - pattern is not really defined as an ( odd-indexed ) argument to the solution function ( some strategically placed backticks would help ), no examples are shown for pattern[matchesSymbol], and it's really only mentioned once, seemingly in passing, after which the focus is immediately moved to something completely different.

    Some more explanation, and maybe an example, would be nice there.

    ( Why do we need to work with pattern[something] instead of just with pattern ?!? )

  • JohanWiltink Avatar

    How does a primitive value match to an Object ?

  • JohanWiltink Avatar

    Treating constructors as normal functions introduces all sorts of weird behaviour, including Errors that have to be caught and ignored.

    Encoding is Boolean as Boolean seems pretty at first glance, but this is not how JS contructors work, and the consequences are dire. Unfortunately, there is no way to distinguish constructors and non-constructor function, but surely some indication to test for either presence in the prototype or return value when applied can be defined, and would make this part of testing much more elegant.

  • JohanWiltink Avatar

    Normal JavaScript behaviour is NaN !== NaN. NaN is not equal to anything, even itself.

    I understand the temptation, but please do not redefine this normal, expected JavaScript behaviour.