7
$\begingroup$

I don’t understand this:

In[]:  AtomQ[Counts[{a, c, d, b, a, c, b}]]     
Out[]:  True

It looks like an expression. Does this have to do with the realization of the expression?

Dani

$\endgroup$
2
  • $\begingroup$ similar: Evaluated vs. unevaluated Association $\endgroup$
    – WReach
    Commented Feb 18, 2020 at 20:07
  • 4
    $\begingroup$ "Everything is an expression" is an ideal not a contract. Some things are treated as atomic objects. Association is one of those. $\endgroup$
    – b3m2a1
    Commented Feb 18, 2020 at 20:16

1 Answer 1

13
$\begingroup$

In the earliest versions of Mathematica, atoms were largely restricted to simple objects which appeared as the leaves within basic head-plus-elements expressions. Such atoms included symbols and strings, along with integer, real, rational and complex numbers. These early atoms had no internal structure beyond their intrinsic value, and hence no expression subparts.

But as the language evolved, it became clear that some types of functionality could not be implemented in an efficient manner using only head-plus-elements. The Association returned by the Counts[...] expression in the question is one such example.

Initially, the solution was to to introduce a specialized object type which was almost indistiguishable from a head-plus-elements expression. An example of this is the packed array (see 3496).

But increasingly the solution has been to introduce new atomic types. Examples include Graph, SparseArray and (as observed in the question) Association. The list of atomic types grows with each release and is now quite long (see 46850 and 202274).

EntityClass["WolframLanguageSymbol", "Atomic"] // EntityList // Length
(* 75 *)

That list is not necessarily complete since at time of writing Symbol is missing from the list.

These new atoms, being atoms, have no subparts in the conventional sense of a symbolic expression. Yet they often had complex internal structure, with many internal properties that may or may not be accessible from the outside. This complex-internals-yet-no-subparts dichotomy can be a source of confusion.

The input forms of some atomic types look like they are a normal head-plus-elements expression, but if you try to access their subparts you will get different results than their appearance would imply. For example Graph (see 4301833):

$g = Graph[{1 -> 2}];

AtomQ[$g]
(* True *)

$g // InputForm

(* Graph[{1, 2}, {DirectedEdge[1, 2]}] *)

$g[[1]]
  (* Part::partd: Part specification Graph[...][[1]] is longer than depth of object. *)

... or Association which simulates part access but only to a certain extent (see 204254):

$a = <| "a" -> 1 |>;

AtomQ[$a]
(* True *)

$a // FullForm
(* Association[Rule["a",1]] *)

$a[[1]]
(* 1, we might have expected Rule["a",1] *)

$a[[1, 1]]
(* Part::partd: Part specification <|a->1|>[[1,1]] is longer than depth of object.
   We might have expected "a" *)

Similarly, SparseArray part access does not conform to its apparent input form:

$sa = SparseArray[{1 -> 10, 3 -> 20}, 500, 999];

AtomQ[$sa]
(* True *)

$sa // InputForm
(* SparseArray[Automatic, {500}, 999, {1, {{0, 2}, {{1}, {3}}}, {10, 20}}] *)

$sa[[3]]
(* 20, might have expected 999 as it is the third part of the input form *)

It is increasingly common for the latest atomic additions to the language to have a graphical display form, the so-called information "raft":

$sa

SparseArray screenshot

To help overcome their opaque nature, atomic types often have specialized operations that can access their otherwise inaccessible internal structures:

VertexList[Graph[{"a" -> "b"}]]
(* {"a", "b"} *)

Keys[<|"a" -> 1|>]
(* {"a"} *)

SparseArray[{1 -> 10, 3 -> 20}, 500, 999]["Background"]
(* 999 *)

To add to the confusion, most of the atomic types are constructed by using basic head-plus-elements expressions that resemble their input forms. Their constructors are not atomic, but their apparently identical input forms are atomic:

AtomQ[<|"a"->1|> // Unevaluated] (* False *)
AtomQ[<|"a"->1|>] (* True *)

AtomQ[Graph[{1->2}] // Unevaluated] (* False *)
AtomQ[Graph[{1->2}]] (* True *)

AtomQ[SparseArray[{1->10, 2->20}] // Unevaluated] (* False *)
AtomQ[SparseArray[{1->10, 2->20}]] (* True *)
$\endgroup$
1
  • $\begingroup$ Thanks a lot! ("Atoms are also symbolic expressions, but they are special in that they are symbolic expressions that don’t have any parts.") $\endgroup$
    – Dani
    Commented Feb 19, 2020 at 17:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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