Data Structures

There are three basic builtin native structures in Citron - Array, Tuple and Map

which are further extended by non-native extensions - Set and Generator

Array

Array is basically a list of values, implemented as a contiguous array.

Its' elements can have any type, and it can be created literally by the push: method.

Array new push: 3, push: 'test', push: Nil

or with a shorthand:

Array < 3 ; 'test' ; Nil

Basic example

var shoplist := Array < 'apple' ; 'mango' ; 'pure chocolate' ; 'old memes'. Pen writeln: 'There are ' + (shoplist count) + ' items to buy.'. Pen writeln: 'Those items are: %:L' % [' ', shoplist]. Pen writeln: 'I also want some programming socks!'. shoplist push: 'programming socks'. Pen write: 'Now I have to buy all of these shticks:\n'. shoplist each: {:idx:name Pen writeln: '\t$$idx - $$name'. }. Pen write: 'Such a bad list, let me sort it first: '. shoplist is shoplist sort: {:a:b # now compare items a and b ^(a length) > (b length). #Whichever has a longer name last }. Pen writeln: '%L' % [shoplist]. Pen writeln: 'I have bought this trash now: %s, and I have these left to buy: %L' % [shoplist shift, shoplist].

Which should give the output

There are 4 items to buy. Those items are: apple mango pure chocolate old memes I also want some programming socks! Now I have to buy all of these shticks: 0 - apple 1 - mango 2 - pure chocolate 3 - old memes 4 - programming socks Such a bad list, let me sort it first: apple, mango, old memes, pure chocolate, programming socks I have bought this trash now: apple, and I have these left to buy: mango, old memes, pure chocolate, programming socks

Tuple

Tuples are - much like other languages that have them - like immutable arrays

Their syntax is quite simple: [ element0, element1 ]

Basic example

var zoo is ['level-headed lion', 'crazy snek', 'memeified pinguin']. Pen writeln: 'There are %d animals in this zoo' % [zoo count]. #Any attempt at changing them deegrades them to an Array (or throws an exception) var zoo1 is ['anime-loving pinguin'] + zoo. Pen writeln: 'This zoo of %s is a very meme-like zoo, but this %s zoo is not!' % [zoo1, zoo]. #They retain their tuple-ness when printed literally #as normal, degraded tuples are just arrays Pen writeln: zoo1 pop. #But don't even try to pop something off them or such Pen writeln: zoo pop.

Output

There are 3 animals in this zoo This zoo of Array ← 'anime-loving pinguin' ; 'level-headed lion' ; 'crazy snek' ; 'memeified pinguin' is a very meme-like zoo, but this ['level-headed lion', 'crazy snek', 'memeified pinguin'] zoo is not! memeified pinguin Uncaught error has occurred. Cannot change immutable array's structure #2 pop (test.ctr: 12) #1 writeln: (test.ctr: 12)

Map

Maps are implemented as HashMaps, and respect the hash method provided by the object object::'iHash'

They do not have any literals associated with them.

Example
#They can be either constructed with Map::'put:at:' var map is Map new put: 'World' at: 'Hello', put: 'Fish' at: 'Dead'. #Or with Map::'cnew:' var map1 is Map cnew: { Hello => 'World'. Dead => 'Fish'. }. #Or with Map::'fromArray:' var map2 is Map fromArray: [ ['Hello', 'World'], ['Dead', 'Fish'] ]. Pen writeln: 'They serialize upon printing by default:\n' + map. # You can add, modify, or remove assocs map put: 'Guy' at: 'Dead'. #That's sad map deleteAt: 'Dead'. #They can contain any object that implements iHash map put: 1 at: 2, put: '1' at: 3, put: map at: 4. #Even themselves Pen writeln: map. #They can be iterated over: map each: {:key:value Pen writeln: '%s, %s' % [key, value]. }. #Or mapped to a map with different values map2 is map fmap: \:key:value key + ', ' + value. Pen writeln: map2.

Output

They serialize upon printing by default: (Map new) put:'Fish' at:'Dead', put:'World' at:'Hello' (Map new) put:':selfReference:' at:4, put:'1' at:3, put:1 at:2, put:'World' at:'Hello' 4, (Map new) put:':selfReference:' at:4, put:'1' at:3, put:1 at:2, put:'World' at:'Hello' 3, 1 2, 1 Hello, World (Map new) put:'Hello, World' at:'Hello', put:'2, 1' at:2, put:'3, 1' at:3, put:'4, (Map new) put:\':selfReference:\' at:4, put:\'1\' at:3, put:1 at:2, put:\'World\' at:\'Hello\'' at:4

Set

Sets are implemented basically as Maps, without values (they have a fixed value, which is shared between all sets).

No literals.

Example

# HashSet import Library/Data/Set/HashSet: 'HashSet'. # or as 'Set': # import Library/Data/Set/HashSet: { HashSet => 'Set'. } var set is HashSet new. # => {} set add: 1, add: 2. # => {2, 1} # Or maybe if you have a bunch set addAll: ['test', 3]. # => {3, 'test', 2, 1} # Remove an element set remove: 'test'. # => {3, 2, 1} # Check if an element exists set contains: 'test'. # => False # Bloom Filter import Library/Data/Set/BloomFilter: 'BloomFilter'. # These sets are neat, they provide a definite not-existence answer only # That is, you cannot retrieve data from them, nor can you reliably remove data from them # But they only contain a Number, and can be a fast low-confidence filter var bf is BloomFilter new. bf add: 'test', add: 'something else', add: 64. # => [BloomFilter] bf contains: 4. # => False bf contains: 'test'. # => True

Generators

Generators are lazy list generators, they have a few helpful basic functionalities as well.

Number..Number and Number..Number..Number exists as a literal (see example)

Example

# You can make a simple step generator with numbers: var gen0 is 0..10. # => [StepGenerator] # With a step value var gen1 is 0..2..10. # => [StepGenerator] # Or through messages to Generator var gen2 is Generator from: 0 to: 10. var gen3 is Generator from: 0 to: 10 step: 2. var gen4 is Generator repeat: Nil. # This will just make `Nil's forever, it's useful to map var gen5 is Generator elementsOf: [1,2,3,4]. # Makes a generator from a collection (Array,Map,String) # You can get the next value gen0 next. # => 0 gen0 next. # => 1 # You can map them to a new generator var gen6 is gen0 fmap: \:x x + 3. # Note that advancing one will advance the other too gen6 next. # => 5 gen0 next. # => 3 # You can return a generator from a mapping, and `inext' will expand it var gen7 is gen4 fmap: \:_ gen0 copy. # make the elements of gen0. forever. gen7 inext. # => 4 gen7 inext. # => 5 (1..10) fmap: \:_ gen7 inext, toArray. # => Array ← 6 ; 7 ; 8 ; 9 ; 10 ; 6 ; 7 ; 8 ; 9 ; 10 # You can break in the middle of a mapping too, which will terminate the generator

List Comprehensions

Everyone likes list comprehensions, so here, you can have them too.

Literal: too many to list, take a look at the example

Example

var list0 is [x,, 1..10]. # Free variables are bound in order # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # You can specify any number of predicates list0 is [x,, 1..10,, (x mod: 4, = 0)]. # Only multiples of 4 # => [4, 8] list0 is [x,, 1..10,, (x mod: 4, = 0), (x > 4)]. # only multiples of 4 bigger then 4 # => [8] # You can do without a source too var conditionally10 is [10,,, False]. # => [] # Note the 3 commas var a is 10. var list1 is [a + x,, 1..3]. # bound names stay as they are # => [11, 12, 13] # More than one source var list2 is [x + y,, [1,2,3], [5,6,7]]. # => Array ← 6 ; 7 ; 8 ; 7 ; 8 ; 9 ; 8 ; 9 ; 10 var list3 is [x + y,, [1,2,3], [5,6,7],, x > y]. # => [] var list4 is [x + y,, 1..3, 5..7]. # => Array ← 6 ; 7 ; 8 ; 7 ; 8 ; 9 ; 8 ; 9 ; 10 # You can specify the names as well var list5 is [x + y,, (y: [1,2,3]), (x: [5,6,7]),, y < x, (x mod: y, < 1)]. # => Array ← 6 ; 7 ; 8 ; 8 ; 9 var list6 is [x + y,, (x: 1..3), (y: 5..7),, y - x < 5] # => Array ← 6 ; 7 ; 8 ; 8 ; 9 ; 10 # You can return any citron object var dispatch is Map fromArray: [[x, {\:arg arg at: x.}],, 1..5]. # returns a 2-tuple of key and a block that calls its argument with that key # => (Map new) put:([:Block]) at:5, put:([:Block]) at:4, put:([:Block]) at:3, put:([:Block]) at:2, put:([:Block]) at:1 # Now call it! dispatch at: 1, applyTo: [1,2,3]. # => 2

TODO: more Strings

<- Prev Next ->