8
$\begingroup$

I'm trying to develop an domain-specific language with Mathematica. I want to define a customized behavior for the Plus function when applied to my data.

For simplifying the problem, let's say that my custom data is of a list of associations.

Unprotect[Plus];
Plus[x_List, y_List] := Join[x, y] // Merge[Total]
Protect[Plus];

Then,

{<|"a" -> 1|>, <|"b" -> 2|>} + {<|"a" -> 2|>}

gives the correct answer with an error message.

Thread::tdlen: Objects of unequal length in {<|a -> 1|>, <|b -> 2|>} + {<|a -> 2|>} cannot be combined. >>

<|"a" -> 3, "b" -> 2|>

How can I avoid the error message? I suspect an evaluation control problem, but I can't find any clues to solve it.

$\endgroup$
  • $\begingroup$ Interesting that an error is not thrown with using an undefined infix operator such as CirclePlus $\endgroup$ – bobthechemist Sep 29 '14 at 12:01
  • 2
    $\begingroup$ If you put DownValues on Plus you will slow down anything that has a Plus in it, by a considerable amount. Either define a new operation myNewListPlus, or do this with UpValues. $\endgroup$ – Daniel Lichtblau Sep 29 '14 at 15:07
  • $\begingroup$ @bobthechemist I guess M tried to evaluate the expr with its own definition first and then with my definition. It's a blind guess. I'm learning M. $\endgroup$ – Y. Kwon Sep 30 '14 at 1:23
  • $\begingroup$ @DanielLichtblau Thank you for the advise. I didn't know about the performance. However, I want it to have a simple and seamless syntax. Could you explain more about using UpValues? I know the syntax and usage but I don't know how to apply it. $\endgroup$ – Y. Kwon Sep 30 '14 at 1:32
  • $\begingroup$ I wonder if people really use upvalues? $\endgroup$ – bobthechemist Sep 30 '14 at 1:34
3
$\begingroup$

Cause

As Junho Lee explains this is due to the Listable attribute of Plus which takes effect before other rules.

The Standard Evaluation Procedure tutorial says:

As soon as the Wolfram System has evaluated the head of an expression, it sees whether the head is a symbol that has attributes. If the symbol has the attributes Orderless, Flat, or Listable, then immediately after evaluating the elements of the expression the Wolfram System performs the transformations associated with these attributes.

Here is a simple example with a user defined function:

SetAttributes[f, Listable];
f[a__] := foo[a]

f[{1, 2, 3}, 4]
{foo[1, 4], foo[2, 4], foo[3, 4]}

Notice how threading was performed before the definition was applied.

Proposal

You wrote: "I want it to have a simple and seamless syntax."

I propose using one of the undefined Operators such as CirclePlus:

CirclePlus[x : {__Association}, y : {__Association}] := Join[x, y] // Merge[Total]

Now:

{<|"a" -> 1|>, <|"b" -> 2|>} ⊕ {<|"a" -> 2|>}
<|"a" -> 3, "b" -> 2|>

The character is entered with Escc+Esc.

$\endgroup$
2
$\begingroup$

The message is due to Listable attribute. I guess that the Listable process call Thread. If you get rid of this attribute, do like this.

Unprotect[Plus];
Plus[x_List, y_List] := Join[x, y] // Merge[Total]
Protect[Plus];

ClearAttributes[Plus, Listable]

Have try this.

{<|"a" -> 1|>, <|"b" -> 2|>} + {<|"a" -> 2|>}

<|"a" -> 3, "b" -> 2|>

But if you maintain the attribute, suggest to use Off[Thead::tdlen] of message off as @mete said.

$\endgroup$
  • $\begingroup$ Given that the listability of Plus is a fundamental property in Mathematica this modification is highly inadvisable, nevertheless I agree with your analysis so +1. $\endgroup$ – Mr.Wizard Oct 30 '14 at 6:45
0
$\begingroup$

You can turn the message off by doing

Off[Thread::tdlen]

You are not really avoiding it, just putting under the carpet

$\endgroup$
  • $\begingroup$ Maybe my english was wrong but I didn't mean this. Thanks,anyway. $\endgroup$ – Y. Kwon Sep 30 '14 at 9:44

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.