11
$\begingroup$

This case revealed I am missing something in pattern matching and evaluation in case of match, or I can't grasp it due to the busy week I have. Either way, I find this problem interesting for wider audience:

asso = <|
    "key" -> <|"a" -> "1", "b" -> Compress@"test"|>
|>

We want to replace the inner association with uncompressed value from "b" key. The expected result is:

<|"key" -> "test"|>

Association is HoldAllComplete so we will have to use Trott-Strzebonski technique or RuleCondition.

The problem is it works but throws a message in between:

asso /. KeyValuePattern[ {"a" -> "1", "b" -> val_String}] :> With[
    {eval = Uncompress[val]}
  , eval /; True
]
 (*or RuleCondition@Uncompress[val]*)
Uncompress::argt: Uncompress called with 0 arguments; 1 or 2 arguments are expected.

<|"key" -> "test"|>

The question is, what am I missing? Recent chat discussion confirms that is not obvious.

I have stuff to do so I'm just using the workaround:

asso /. sub : KeyValuePattern[{"a" -> "1", "b" -> _String}
] :>   RuleCondition @ Uncompress @ sub @ "b"

but I don't get the difference that makes it work.

$\endgroup$
3
  • 1
    $\begingroup$ The With code does not give the uncompressed output in Open Cloud. asso /. KeyValuePattern[{"a" -> "1", "b" -> val_String}] :> RuleCondition @ Uncompress @ val does give the uncompressed output but also issues a message. Which part of this is more interesting to you? $\endgroup$
    – Mr.Wizard
    Jun 30, 2017 at 6:43
  • $\begingroup$ @Mr.Wizard The point is, I want to be comfortable using KeyValuePattern. At the moment I'm not. So any insight is on topic. Also, as pointed out I don't see the reason why my workaround works so I'd say the open cloud kernel is closer to me ;) $\endgroup$
    – Kuba
    Jun 30, 2017 at 6:49
  • $\begingroup$ The same weird behaviour prevents replacement in this code: <|0 -> 0, 1 -> 2|> /. KeyValuePattern[{a_ -> b_, c_ -> d_}] :> (1 /; {d} =!= {c}) even though the condition is True. $\endgroup$
    – Coolwater
    Jun 30, 2017 at 11:35

1 Answer 1

7
$\begingroup$

The output of this code in Open Cloud seems to reveal what is happening:

<|"a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4|> /.
  KeyValuePattern[{"a"->v1_, "b"->v2_, "c"->v3_, "d"->v4_, "x"->v5_}] :> 
    "foo" /; (Print[{v1},{v2},{v3},{v4},{v5}];True)

{1}{}{}{}{}

{1}{2}{}{}{}

{1}{2}{3}{}{}

{1}{2}{3}{4}{}

<|a->1,b->2,c->3,d->4|>

So we can see that the expression is incrementally tested for partial matches.

Rather like:

{1, 2, 3, 4} /. {x__, ___} :> "foo" /; Print[{x}]

{1}

{1,2}

{1,2,3}

{1,2,3,4}

{1, 2, 3, 4}

This is how we get Uncompress[] in your evaluation as val_String is given a null (vanishing) match in the first attempt.

$\endgroup$
15
  • $\begingroup$ But why partial matches are considered match? And if it is only due to the condition, why this does not leak: f[x_Real] := Echo[x^2]; Hold[{Hold[2.], Hold[3.], Hold["string"]}] /. n_Real :> With[{eval = f[n]}, eval /; True] $\endgroup$
    – Kuba
    Jun 30, 2017 at 7:30
  • $\begingroup$ @Kuba I don't know; this is the first time I have looked at KeyValuePattern. I presume it is part of KeyValuePattern's design, perhaps necessitated by its unusual matching behavior. $\endgroup$
    – Mr.Wizard
    Jun 30, 2017 at 7:32
  • $\begingroup$ My claim is that either both leak (KeyValuePattern and the example from the comment) or neither. Otherwise this inconsistency is more than a design choice. This or I still miss something. $\endgroup$
    – Kuba
    Jun 30, 2017 at 7:34
  • $\begingroup$ @Kuba But KeyValuePattern does not work like a simple _ pattern. It specifically allows things like MatchQ[<|a -> 1, b -> 2, c -> 3|>, KeyValuePattern[b -> 2]] (True) which implies ___-like aspects. $\endgroup$
    – Mr.Wizard
    Jun 30, 2017 at 7:37
  • $\begingroup$ This too but it does not leak: Hold[{{a -> 1, b -> "string", c -> 3}, {a -> 1, b -> 2, c -> 3}}] /. {___, b -> i_Integer, ___} :> With[{eval = Echo[i^2]}, eval /; True] $\endgroup$
    – Kuba
    Jun 30, 2017 at 7:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.