2

Can we construct a function Iceberg,
which maps a given expression X to Iceberg[X]
satisfying 1. and 2. and 3. ?

1. From Iceberg[X],
it is not possible to inspect/extract a part of X with usual method.
It would be better if there is no part of Iceberg[X].
Applying Iceberg to X is like putting X into an iceberg.

ex) It is not difficult to extract 3rd part of {101,102,103,104,105},
from Hold[{101,102,103,104,105}].

    In[1]  Hold[{101,102,103,104,105}][[1]][[3]]
Out[1] 103

So Hold is not like Iceberg.

Likewise, for HoldComplete, Unevaluate, Defer, Inactivate, ... and combinations of these commands, similar method can extract any part of X.

So they are not like Iceberg.

2. From Iceberg[X], there is a unique way to comeback to X.

In[2]  Icemelt[Iceberg[{101,102,103,104,105}]]
Out[2]  {101,102,103,104,105}

No function other than 'Icemelt', can do it.

3. In fact there is a function satisfying 1. and 2. :
Iceberg = ToString
Icemelt = ToExpression

But I ask you to find another solution.

I believe ToString/ToExpression is the only solution.

Michael E2
  • 235,386
  • 17
  • 334
  • 747
imida k
  • 4,285
  • 9
  • 17
  • 3
    "I believe ToString/ToExpression is the only solution." -- Also, Encrypt / Decrypt. – Anton Antonov Jun 11 '21 at 08:41
  • 3
    also Compress/Uncompress? – kglr Jun 11 '21 at 08:51
  • Until a while ago, I've thought 'making expressions to a strings, and do something(joining, splitting, ... ) to those strings, and comeback to expressions is unnatural, ugly way of programming'. – imida k Jun 11 '21 at 09:26
  • 'I should prefer to use Hold, Defer, Inactivate.. because it looks much more professional' – imida k Jun 11 '21 at 09:26
  • But now, I think 1) convert to string 2) do something 3)back to expression method is just good. – imida k Jun 11 '21 at 09:27
  • Because is ToString makes an expression more stable than any combination of evaluation-related built-in functions like Hold,Defer,... – imida k Jun 11 '21 at 09:30
  • 1
    1. Strings are easier to reason with -- they are simple structures, familiar, present in many programing languages. 2. Because strings are simple their application is limiting. 3. It is not clear what is your end goal. If strings let you achieve it faster or easier then use strings. – Anton Antonov Jun 11 '21 at 09:50
  • My goal was making a function whose input is a friendly readable loop pseudocode and output is actual working loop code. The method uses joining strings like "If[" or "]]]" or "Goto[" extensively. – imida k Jun 11 '21 at 10:40
  • As a user, I dislike this sort of thing, but the question has been asked and answered here: https://mathematica.stackexchange.com/questions/198378/custom-atomic-expressions-modern-tutorial – Michael E2 Jun 11 '21 at 18:09
  • 1
    @b3m2a1's myObj[] function does what Iceberg[] is supposed to, and we can define Icemelt[myObj[data_]] := data to get #2. – Michael E2 Jun 11 '21 at 18:21
  • 4
  • I came across this in the review queue. I did not vote to close yet, but I wanted to note that this is a very strange question without context, and I don't see how it would help any future reader. Sure, there are many functions that satisfy your conditions, as pointed out by the first few comments. Presumably you have a motivation for asking this, which should be clarified. See also https://en.wikipedia.org/wiki/XY_problem – Szabolcs Jun 18 '21 at 10:18
  • In principle, one can always write an equivalent to ToExpression, Decrypt, Uncompress, BinaryDeserialize, etc. from scratch, so in this sense, they're not unique. – swish Sep 17 '22 at 07:17

3 Answers3

4
ClearAll@Iceberg;
expr : HoldPattern[Iceberg[x_]] /; ! AtomQ[Unevaluated[expr]] := 
 System`Private`SetNoEntry[Unevaluated[expr]];
Iceberg /: MakeBoxes[v_Iceberg?AtomQ, fmt_] := 
 InterpretationBox[
  RowBox[{"Iceberg", "[", "\[LeftAngleBracket]", "\[RightAngleBracket]", "]"}], v];
Icemelt[HoldPattern[Iceberg[x_]]] := x

Now you can do

Iceberg[{1,2,3}]

enter image description here

I believe it satisfies the other requirements

In[80]:= Iceberg[{101, 102, 103, 104, 105}][[1]][[3]]

During evaluation of In[80]:= Part::partd: Part specification Iceberg[[LeftAngleBracket][RightAngleBracket]][[1]] is longer than depth of object.

During evaluation of In[80]:= Part::partw: Part 3 of Iceberg[[LeftAngleBracket][RightAngleBracket]][[1]] does not exist.

Out[80]= Iceberg[{101, 102, 103, 104, 105}][[1]][[3]]

In[81]:= Icemelt[Iceberg[{101, 102, 103, 104, 105}]]

Out[81]= {101, 102, 103, 104, 105}

Jason B.
  • 68,381
  • 3
  • 139
  • 286
  • This doesn't guard you from pattern matching in general, so IceMelt is not unique: Replace[Iceberg[{1,2,3}],Verbatim[Iceberg][x_]:>x]. I'm looking for something similar, that also prevents anyone from looking at insides with pattern matching, but everything is still visible in InputForm. Like Graph, I don't understand how graph works, it is AtomQ, EntryQ, and without WXF type, but it prevents looking inside of it with every other means, without some BinarySerialize/BinaryDeserialize like hacks of course. – swish Sep 16 '22 at 20:59
  • @swish - I am not aware of any method to do what you want without implementing it in the kernel C code, like Graph. – Jason B. Sep 16 '22 at 22:13
2

Silly, but fun

X = {101, 102, 103, 104, 105};

img = Rasterize[X];

ToExpression[TextRecognize[img]] === X (* True *)

mikado
  • 16,741
  • 2
  • 20
  • 54
  • This is, great :) I was thinking that it will be an interesting challenge to list or enumerate all possible ways to do the "icebergs" in WL. – Anton Antonov Jun 11 '21 at 19:14
0

So this seems to come close to satisfying all the properties, including Icemelt uniqueness. I don't know any method to hack this Iceberg at this point, but I'll think about it more. If someone knows a hack please let me know:

(* hold attribute helpers *)

HoldPosition[sym_Symbol[args___]] := With[{attrs = Attributes[sym], len = Length @ Unevaluated @ {args}}, Which[ MemberQ[attrs, HoldFirst], {1}, MemberQ[attrs, HoldRest], Range[2, len], MemberQ[attrs, HoldAll | HoldAllComplete], Range @ len, True, {} ] ]

HoldPosition[_] := Missing["Position"]

HoldPositionQ[expr_, i_] := With[{pos = HoldPosition[Unevaluated[expr]]}, MissingQ[pos] || MemberQ[pos, i]]

SequenceHoldQ[sym_Symbol[___]] := MemberQ[Attributes[sym], SequenceHold] SequenceHoldQ[_] := False

(* Icemelt *)

(* always melt with StackComplete *) Icemelt[Verbatim[Iceberg][data_]] /; MemberQ[Stack[], StackComplete] := data Icemelt[iceberg_Iceberg] := StackComplete[Icemelt[iceberg]] Icemelt[expr___] := $Failed

(* Iceberg *)

Iceberg::unbrk = "is unbreakable with ``"; Iceberg::symbol = "attempt at reading iceberg symbol is detected";

(* run this if anything except Icemelt is executed with Iceberg in it *) Iceberg /: expr : (f : Except[Icemelt])[left___, iceberg_Iceberg, right___] /; ! SequenceHoldQ[Unevaluated[expr]] := With[{ i = Length[HoldComplete[left]] + 1 }, ( Message[Iceberg::unbrk, HoldForm[DisableFormatting[f[left, Iceberg["[Ellipsis]"], right]]]]; $Failed ) /; ! HoldPositionQ[Unevaluated[expr], i] ]

(* formatting *) Iceberg /: MakeBoxes[iceberg_Iceberg, fmt___] := With[{data = StackComplete @ Icemelt[iceberg]}, BoxForm`ArrangeSummaryBox["Iceberg", "Iceberg"["[Ellipsis]"], Style["", 48], {{}}, {{data}}, fmt] ]

(* make Iceberg atomic *) Iceberg /: iceberg_Iceberg /; SystemPrivateHoldEntryQ[iceberg] := SystemPrivateHoldSetNoEntry[iceberg]

(* make an Iceberg with protected symbol that only returns its data inside Icemelt *) iceberg : Iceberg[data_] /; SystemPrivateHoldNotValidQ[iceberg] := Module[{var}, var := If[MemberQ[Stack[], Icemelt], data, Message[Iceberg::"symbol"]; $Failed]; SetAttributes[var, {Protected, ReadProtected, Locked}]; SystemPrivateHoldSetValid[Iceberg[var]] ]

(* protect and lock it *) SetAttributes[Iceberg, {ReadProtected, Protected, Locked, HoldAllComplete}]

Here is notebook with an example: https://www.wolframcloud.com/obj/nikm/Published/Iceberg.nb

swish
  • 7,881
  • 26
  • 48
  • This seems interesting as an academic exercise only. You can't even put your object inside a list without it complaining: {Iceberg[{1, 2, 3}], Iceberg[{1, 2, 3}]}. I think you would have a hard time doing anything useful with it – Jason B. Sep 17 '22 at 10:20
  • @JasonB. That's perfectly ok, it's intended to be held. You gotta support your iceberg by holding it at all costs :) – swish Sep 17 '22 at 13:23
  • @JasonB. Also a relaxation can be made with an additional condition ValueQ[Unevaluated[expr]] that will allow pure structural modification like wrapping lists and other symbols around icebergs. – swish Sep 17 '22 at 13:35