Infix form of PutAppend ( >>> ) does not work with variable
I believe it does work, just not how you expect. :-)
From the documentation for PutAppend
:
Note that there are no quotation marks around filename
in the first line.
It is not made particularly clear but you can use this syntax with >>>
:
Range[10] >>> file.txt
Which outputs to a file named file.txt
directly. This is a special and unusual parsing, used also for >>
(Put
) and <<
(Get
).
Because of this your results are being sent to a file named filenameS
rather than one named according to the string value of filenameS
.
Usually file.txt
would be interpreted as Dot[file, txt]
, but in the case of >>>
it is parsed differently. Here is a low-level look at what is going on. parseString
(1) parses as string using the Front End into Box form.
parseString[s_String, prep : (True | False) : True] :=
FrontEndExecute @ FrontEnd`UndocumentedTestFEParserPacket[s, prep]
"data >>> file.txt" // parseString
"data :> file.txt" // parseString
{BoxData[RowBox[{"data", ">>>", "file.txt"}]], StandardForm} {BoxData[RowBox[{"data", ":>", RowBox[{"file", ".", "txt"}]}]], StandardForm}
Note the different handling. Here RuleDelayed was used as an arbitrary "normal" operator.
As further illustration of the special parsing we can demonstrate that neither Function
nor With
can effect the substitution. This outputs to a file named x
rather than myfile.txt
:
With[{x = "myfile.txt"},
Range[5] >>> x
]
This isn't even valid input:
(Range[5] >>> #) &["myfile.txt"]
Syntax::sntxf: "(" cannot be followed by "Range[5]>>>#)".
Syntax::tsntxi: "Range[5]>>>#" is incomplete; more input is needed.
Nevertheless we can attempt to override the behavior with $PreRead
or MakeExpression
which work at the Box level:
MakeExpression[RowBox[{lhs_, ">>>", rhs_String}], form_] :=
MakeExpression[
RowBox[{"PutAppend", "[", RowBox[{lhs, ",", rhs}], "]"}],
form
] /; ! StringMatchQ[rhs, "\"*\""]
Now any appearance of lhs >>> rhs
where rhs
is not a string should behave as PutAppend[lhs, rhs]
, assuming I wrote the rule correctly.
Mr. Wizard's answer is basically correct. I was originally going to just edit his answer, but I decided this is a bit too much to do that. Mr. Wizard, feel free to delete my answer and just incorporate this info into yours.
There are six special "auto-stringifying" operators, namely:
>> >>> << :: ? ??
These parse the argument to their right. If the argument is a string, they they will slurp up that whole string. If the argument isn't a string, they will read until they've reached the end of a file name (as defined in Operator Input Forms) for the first three or a symbol for the last 3. This argument is then converted to a string before any evaluation happens. Indeed,
In[38]:= Hold[<< foo] // InputForm
Out[38]//InputForm= Hold[Get["foo"]]
and
In[43]:= foo::bar::English//FullForm
Out[43]//FullForm= MessageName[foo,"bar","English"]
Because this happens deep in the parser (converter of boxes or text to Wolfram Language expressions) before any evaluation happens, there really is no way to change this short of something like the MakeExpression
rule proposed by Mr. Wizard. Of course, then something like a >>> myfile.txt
will no longer work after that change.
You call always used the head[args]
form if you want to use any arbitrary expression. Incidentally, both ?
and ??
are different forms of Information
.