Skip to main content

programming - Is Package development (via InitializationCells) compatible with creating new Notations (via MakeExpressions)?


Can new (lower-level) notations be readily used within package code?


There are a few notational additions that might improve my code base but I'm not sure if these will end up being more trouble than they are worth.


For example, take a first step in an attempt to implement a more “natural” and “efficient” struct; Using MakeExpression


MakeExpression[RowBox[{lhs___, x__, "\[CenterDot]", y__, rhs___}],StandardForm] := 
MakeExpression[RowBox[{lhs, RowBox[{x, "[", y, "]"}], rhs}],StandardForm];

yields a more OO-like notation


In[2]:= obj."field1"."field2"



Out[2]:= obj["field1"]["field2"]


[Here the . is mimicking Mma's \[CenterDot] -SE won't let newbies post images)]


In any (frontend) package development however, placing obj."field1"."field2" within an initialization cell causes this exact form to be placed in the corresponding .m file. It is this form that is subsequently loaded in by Get i.e. without any of the frontend parsing provided by the MakeExpression definition.


Hence the intended notation does not take effect in packages (instead CenterDot in CenterDot[obj,"field1","field2"] becomes unintentionally defined but a priori I want to avoid overloading CenterDot for efficiency/inheritance/encapsulation reasons).


One hack is to forcibly activate the frontend's parser while loading in packages by invisibly opening up the .m file and evaluating all initialization cells - something along the lines of:


ParsingGet[pathTomFile_] := With[{nb = NotebookOpen[pathTomFile, Visible -> False]},
FrontEndTokenExecute[nb, "EvaluateInitialization"];
NotebookClose@nb]

This then creates such messiness as having to explicitly integrate with Get's package name arguments, multi-argument BeginPackage calls, "stub symbols" and avoiding developmental surprises such as obj."field1"."field2" not reflecting package updates in single frontend tests such as (ParsingGet[mfilepath]; obj."field1"."field2") (the kernel will grab obj."field1"."field2" and not let go).



I’m a bit wary of going down a path that seems to quickly set off a series of cascading hacks but on the other hand I’m wondering if I’ve missed something (an InitializionCell-like option value?) or if anyone has extensively used such notational (or perhaps more accurately language) changes in package development?


One might expect they should be able to play nicely together since a whole package has been devoted to these lower-level notations in Mma (Jason Harris’s Notation package) and anyone going down this more involved notational route would surely want to harness them in their own packages at some point?



Answer



"these will end up being more trouble than they are worth." - to my mind, this is a very accurate assessment of the situation.


As far as syntax is concerned, you will face multiple obstacles, starting from package and front-end parser differences you outlined (which makes the use of e.g. Notation package in packages quite non-trivial if not problematic), and ending with the limitations of the Notation package itself. If you need a pre-processor to change some of the Mathematica syntax, the general solution would require a full Mathematica parser with modifiable grammar, something like preprocessors in some functional languages (camlp4 in Ocaml for example). Everything else (including the Notation package) will have lots of limitations.


What is worse, is that you seem to be willing to add some OO features, and even if you succeed with the syntax, you will run into the problems of semantics. And these are, I believe, unsolvable without adding a certain amount of native OO support to Mathematica. There were a number of discussions regarding OO in Mathematica, here are some links:


Struct-equivalent-in-mathematica


Struct-data-type-in-mathematica


Object-oriented-mathematica-programming


Question-on-setting-up-a-struct-in-mathematica-safely



Mathematica-oo-system-or-alternatives


which you may want to check out.


EDIT


To be a bit more constructive and illustrate what can be involved in making Notation work in packages, here is a link to a Mathgroup thread where I described one possible way to use it.


Comments

Popular posts from this blog

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...