Compound data type: Difference between revisions

Content added Content deleted
(Added Quackery.)
Line 1: Line 1:
{{task|Basic language learning}}
{{task|rBasic language learning}}
{{Data structure}}
{{Data structure}}


Line 1,884: Line 1,884:


>>></lang>
>>></lang>

=={{header|Quackery}}==

The single ubiquitous compound data type in Quackery is the ''nest'' (a ''mostly'' immutable dynamic array), a sequence of items wrapped in square brackets. (''Mostly'' immutable; i.e. immutable except under limited circumstances beyond the scope of this discussion. When we refer to changing the contents of a nest here, this is casual speech; a shorthand for saying "creating a new instance of the nest, identical the previous instance except where it differs".)

Presented here are two solutions to the task, the "quick and dirty" solution; sufficient to the task described here, and the "overkill" solution; extending the Quackery compiler to facilitate complex compound data structures akin to structs.

===Quick and Dirty===

The word <code>point</code> creates an instance of a nest with two elements, both initialised to zero. The word <code>x</code> specifies the location of the zeroth element within the nest, and the word <code>y</code> specifies the location of the first element within the nest. <code>peek</code> returns the value stored in a specified location, and <code>poke</code> changes the value stored in a specified location, returning the modified nest.

<lang Quackery>
[ ' [ 0 0 ] ] is point ( --> [ )

[ 0 ] is x ( --> n )

[ 1 ] is y ( --> n )

point
dup x peek echo cr
99 swap y poke
y peek echo cr</lang>

{{out}}

<pre>0
99</pre>

===Overkill===

The "overkill" solution automates the process of creating new structures with the word <code>struct{</code>, which extends the Quackery compiler to allow the definition of complex compound data structures as follows.

<lang Quackery> struct{
item.0
{ item.1.0
item.1.1
{ item.1.2.0
item.1.2.1
item.1.2.2
item.1.2.3
} item.1.2
item.1.3
} item.1
item.2
}struct mystruct</lang>

Once defined, the word <code>mystruct</code> will place a new instance of the described structure, with each item initialised to <code>null</code>, on the stack. (The behaviour of <code>null</code> is to place a reference to itself on the stack, as a convenience for debugging, and to allow code to identify elements within the structure that have not had a value assigned to them.)

The various names defined within the struct (e.g. <code>item.1.2.1</code>) return a ''path'' - a means of locating a specific item within the struct, for use by <code>{peek}</code> and <code>{poke}</code>, which have the same behaviours as <code>peek</code> and <code>poke</code>, except the they take a path to an item within a struct as an argument, rather than a number specifying an item within a nest.

Names following a <code>}</code> within the definition of a struct (e.g. <code>} item.1.2</code>) return a path to the compound data structure preceding it within the structure. In the example, <code>item.1.2</code> returns the path to <code>{ item.1.2.0 item.1.2.1 item.1.2.2 item.1.2.3 }</code>

<lang Quackery> mystruct ( create new instance of a mystruct )
dup echo cr ( this is what it looks like )
789 swap item.1.3 {poke} ( change one of the items )
dup echo cr ( this is what it looks like now )
item.1.3 {peek} echo cr ( retrieve the specified item )
</lang>

{{out}}

<pre>[ null [ null null [ null null null null ] null ] null ]
[ null [ null null [ null null null null ] 789 ] null ]
789</pre>

The words <code>{peek}</code>, <code>{poke}</code>, <code>null</code>, and the building word (i.e. compiler extension) <code>struct{</code> defined:

<lang> [ witheach peek ] is {peek} ( { p --> x )

[ dip dup
witheach [ peek dup ]
drop ] is unpack ( { p --> * )

[ reverse
witheach
[ dip swap poke ] ] is repack ( * p --> { )

[ dup dip
[ rot dip
[ unpack drop ] ]
repack ] is {poke} ( x { p --> { )

[ this ] is null ( --> [ )

[ stack ] is {}.path ( --> s )
protect {}.path

[ stack ] is {}.struct ( --> s )
protect {}.struct

[ nextword dup
$ "" = if
[ $ "Unexpected end of struct."
message put
bail ] ] is {}.checknext ( [ $ --> [ $ $ )

[ dup $ "{" =
over $ "}" = or
swap $ "}struct" = or if
[ $ "Name missing after }."
message put
bail ] ] is {}.checkname ( [ $ $ --> [ $ )

[ nested
namenest take
join
namenest put
' [ ' ]
{}.path share nested join
actiontable take
1 stuff
actiontable put ] is {}.addpath ( [ $ $ --> [ $ )

[ nested
namenest take
join
namenest put
' [ ' ]
{}.struct share nested join
actiontable take
1 stuff
actiontable put ] is {}.addstruct ( [ $ $ --> [ $ )

[ {}.path take
dup -1 peek
1+
swap -1 poke
-1 join
{}.path put
[] {}.struct put ] is {}.{ ( [ $ --> [ $ )

[ {}.struct size 3 < if
[ $ "Badly formed struct."
message put bail ]
trim {}.checknext
dup {}.checkname
{}.path take
-1 split drop
{}.path put
{}.addpath
{}.struct take
{}.struct take
swap nested join
{}.struct put ] is {}.} ( [ $ --> [ $ )

[ {}.path take
dup -1 peek
1+
swap -1 poke
{}.path put
{}.addpath
{}.struct take
' [ null ] join
{}.struct put ] is {}.name ( [ $ --> [ $ )

[ trim {}.checknext
{}.struct size
2 != if
[ $ "Badly formed struct."
message put
bail ]
{}.addstruct ] is {}.}struct ( [ $ --> [ $ )

[ ' [ -1 ] {}.path put
[] {}.struct put
[ trim {}.checknext
dup $ "{" = iff
[ drop {}.{ ] again
dup $ "}" = iff
[ drop {}.} ] again
dup $ "}struct" = iff
[ drop {}.}struct ] done
{}.name again ]
{}.struct release
{}.path release ] builds struct{ ( [ $ --> [ $ )</lang>

Finally we use <code>struct{</code> etc. to fulfil the requirements go the task.

<lang Quackery> struct{ x y }struct point
point
dup x {peek} echo cr
99 swap y {poke}
y {peek} echo cr</lang>

{{out}}

<pre>null
99
</pre>


=={{header|R}}==
=={{header|R}}==