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$
  • 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 '17 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 '17 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 '17 at 11:35
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$
  • $\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 '17 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 '17 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 '17 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 '17 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 '17 at 7:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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