ANY CONTAINER IN ANY CONTAINER

Real data is nested. A school has classes, a class has students, and each student has a score for each subject. In satellite any container can hold any other container, to any depth, and the declaration says exactly what goes where. This post builds one, reaches into it, and then asks satl how to reach into it.

One declaration, three levels

Read the type from the outside in: a map from class names to lists, and each list holds maps from subjects to scores. The whole thing can be written in one literal. Braces with key: value entries are a map, and braces without them are a list.

school.satlSATELLITE 004 Download
A map of lists of maps, filled, read and changed
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.container.map<satellite.variable.string, satellite.container.list<satellite.container.map<satellite.variable.string, satellite.variable.number>>> school = {"7A": {{"maths": 81, "art": 64}, {"maths": 72, "art": 90}}}
    school["7A"].append({"maths": 55, "art": 70})
    school["7B"] = {{"maths": 99, "art": 58}}

    satellite.console.display(school["7A"][2]["art"])
    school["7A"][1]["maths"] = 84
    satellite.console.display(school["7A"][1])
    satellite.console.display(school["7A"].size)
    satellite.console.display(school.keys)
    satellite.return(satellite)
}
OUTPUT
90
{"maths": 84, "art": 64}
3
{"7A", "7B"}

Each [ ] steps one level down, left to right. school["7A"] is a list of students. school["7A"][2] is the second student, a map, because a list counts from 1. school["7A"][2]["art"] is that student’s art score. Writing works the same way: school["7A"][1]["maths"] = 84 changes one number deep inside, and .append on a list inside adds a student to that class.

Checked all the way down

What you declare is a promise, and satl holds you to it on every way in: in the literal, in .append, and in a write three levels down. A score is a number, so a string cannot go there.

school_wrong.satlSATELLITE 004 Download
A string where the declaration says a score goes
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.container.map<satellite.variable.string, satellite.container.list<satellite.container.map<satellite.variable.string, satellite.variable.number>>> school = {"7A": {{"maths": 81}}}
    school["7A"][1]["maths"] = "top of the class"
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S301: TYPES_DO_NOT_MEET
satl(run): in school[...] = ..., the value does not fit: it holds a string

directory: school_wrong.satl:6
syntax: school["7A"][1]["maths"] = "top of the class"
              /\

this operator has no scenario for the two kinds it was given. Nothing was
guessed at, because a guess here is an answer that is wrong and does not say so.
machine code 27 types_do_not_meet -- satl exits with this.

--------------------------------------------------------------------------------

Asking satl how to reach in: satellite.access

With a shape this deep it is easy to lose track of which [ ] is which. satellite.access(name) answers that from the declaration. It says what the name is and what it holds, gives one line for each level you can reach, and gives one line that fills each level with a value of the right shape.

school_access.satlSATELLITE 004 Download
What school is, and the code for every level of it
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.container.map<satellite.variable.string, satellite.container.list<satellite.container.map<satellite.variable.string, satellite.variable.number>>> school = {"7A": {{"maths": 81, "art": 64}}}
    satellite.access(school)
    satellite.return(satellite)
}
OUTPUT
school is a map (string -> list of maps (string -> number)), 1 key
  value                             {"7A": {{"maths": 81, "art": 64}}}
  school["key"]                     a list of maps (string -> number), "key" a string, one of "7A"
  school["key"][n]                  a map (string -> number), n counting from 1
  school["key"][n]["key2"]          a number, "key2" a string
  school["key"] = {{"key": 1}}      puts a list of maps under "key"
  school["key"].append({"key": 1})  adds a map
  school["key"][n]["key2"] = 1      puts a number under "key2"
  school.size                       how many keys it holds
  school.keys                       the keys of it, as a list
  school["key"][n].keys             the keys of a map, as a list

n stands for a position, counting from 1, and "key" and "key2" stand for keys. The second column says what each line reaches. None of it is guessed: satl’s tests generate thousands of container shapes, ask satellite.access about each one, and run every line it prints as code.

When an item does not fit

Here is a real first attempt at a deep container. It declares a list of lists of maps, and then appends {{"hello"}}:

crazy_container.satlSATELLITE 004 Download
An append whose item is not the shape the list holds
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.container.list<satellite.container.list<satellite.container.map<satellite.variable.string, satellite.container.list<satellite.container.list<satellite.variable.string>>>>> crazy_container
    crazy_container.append({{"hello"}})
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S301: TYPES_DO_NOT_MEET
satl(run): in crazy_container, crazy_container.append: item 1 of it does not
fit: it holds a list

directory: crazy_container.satl:6
syntax: crazy_container.append({{"hello"}})
        /\

this operator has no scenario for the two kinds it was given. Nothing was
guessed at, because a guess here is an answer that is wrong and does not say so.
machine code 27 types_do_not_meet -- satl exits with this.

--------------------------------------------------------------------------------

The declaration is right. The item is what went wrong: each item of crazy_container is a list of maps, and {"hello"} is a list, not a map. satl never guesses what a line was meant to say, but it knows the declaration, so satellite.access(crazy_container) shows the line that fits. The item needs a key before its lists:

crazy_container_fixed.satlSATELLITE 004 Download
The same container, filled the way satellite.access shows
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.container.list<satellite.container.list<satellite.container.map<satellite.variable.string, satellite.container.list<satellite.container.list<satellite.variable.string>>>>> crazy_container
    crazy_container.append({{"greeting": {{"hello"}}}})
    satellite.console.display(crazy_container[1][1]["greeting"][1][1])
    satellite.access(crazy_container)
    satellite.return(satellite)
}
OUTPUT
hello
crazy_container is a list of lists of maps (string -> list of lists of strings), 1 item
  value                                           {{{"greeting": {{"hello"}}}}}
  crazy_container[n]                              a list of maps (string -> list of lists of strings), n counting from 1 (1 to 1)
  crazy_container[n][m]                           a map (string -> list of lists of strings), m counting from 1
  crazy_container[n][m]["key"]                    a list of lists of strings, "key" a string
  crazy_container[n][m]["key"][p]                 a list of strings, p counting from 1
  crazy_container[n][m]["key"][p][q]              a string, q counting from 1
  crazy_container.append({{"key": {{"text"}}}})   adds a list of maps
  crazy_container[n].append({"key": {{"text"}}})  adds a map
  crazy_container[n][m]["key"] = {{"text"}}       puts a list of lists of strings under "key"
  crazy_container[n][m]["key"].append({"text"})   adds a list of strings
  crazy_container[n][m]["key"][p].append("text")  adds a string
  crazy_container.size                            how many lists of maps it holds
  crazy_container[n][m].keys                      the keys of a map, as a list

Where next

Each container on its own: LISTS, GRIDS: LISTS OF LISTS, MAPS and MULTIPLE: ONE NAME, SEVERAL TYPES. satellite.access and the switch behind it are in HISTORY AND ACCESS, and every container word is in the FULL REFERENCE.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *