3.23. kink/VEC

Companion mod for vec vals.

3.23.1. type vec

A vec val is a mutable and variable-length sequence of vals.

Elements of a vec are indexed using consequent int nums starting from 0.

If a vec is accessed from multiple threads, write/write or write/read pairs must be serialized using MUTEX, CHAN or other ways.

There are vaious usages for vecs in Kink, for example, as traits and as maybe_vec vals.

As traits:

It is a idiom to store sym-val pairs as a vec, then spread it when calling CORE.new_val fun. Such an array is called a trait. Example:

# make a rational val
:new_rational <- {(:Numer :Denom)
  new_val(
    # reuse Rational_trait, which is common to all rational vals
    ... Rational_trait

    # Numer and Denom differ for each rational val
    'Numer' Numer
    'Denom' Denom
  )
}

# trait for rational vals
:Rational_trait <- [
  'numer' {[:R]() R.Numer }
  'denom' {[:R]() R.Denom }
  'repr' {[:R]()
    '{}/{}'.format(R.numer R.denom)
  }
]

stdout.print_line(new_rational(2 3).repr)  # => 2/3
stdout.print_line(new_rational(4 5).repr)  # => 4/5

As maybe_vec vals:

An maybe_vec is a vec with 1 or 0 element, which represents a val which may or may not exist. For example, Str.search_slice returns a maybe_vec.

:attempt_search <- {(:Str :Min_ind :Slice)
  Str.search_slice(Min_ind Slice).for_maybe(
    {(:Ind) stdout.print_line('found at: {}'.format(Ind.repr)) }
    { stdout.print_line('not found') }
  )
}
attempt_search('foofoo' 2 'oo')  # => found at: 4
attempt_search('foofoo' 5 'oo')  # => not found

A vec is a subtype of plain_param. See kink/param/PLAIN_PARAM mod.

Vec.get(Ind)

Vec.get(Ind) returns the specified element of the Vec.

Precondition:

• Ind must be an int num in the range [0, Vec.size)

Example:

:Vec <- ['foo' 'bar' 'baz']
stdout.print_line(Vec.get(0).repr)  # => "foo"
stdout.print_line(Vec.get(1).repr)  # => "bar"
stdout.print_line(Vec.get(2).repr)  # => "baz"

Vec.size

Vec.size returns the size, which is the number of the elements of the Vec.

Example:

:Vec <- ['foo' 'bar' 'baz']
stdout.print_line(Vec.size.repr)  # => 3

Vec.empty? nonempty?

Vec.empty? and nonempty? return whether or not the size of the Vec is 0.

Example:

stdout.print_line([].empty?.repr)     # => true
stdout.print_line([].nonempty?.repr)  # => false

stdout.print_line(['foo' 'bar' 'baz'].empty?.repr)    # => false
stdout.print_line(['foo' 'bar' 'baz'].nonempty?.repr) # => true

Vec.front

Vec.front returns the first element of the Vec.

Precondition:

• Vec must be nonempty

Example:

stdout.print_line(['foo' 'bar' 'baz'].front)  # => "foo"

Vec.back

Vec.back returns the last element of the Vec.

Precondition:

• Vec must be nonempty

Example:

stdout.print_line(['foo' 'bar' 'baz'].front)  # => "baz"

Vec.set(Ind Val)

Vec.set stores the Val at the specified Ind.

Precondition:

• Ind must be an int num in the range [0, Vec.size)

Example:

:Vec <- ['foo' 'bar' 'baz']
Vec.set(1 'X')
stdout.print_line(Vec.repr) # => ["foo" "bar" "baz']

Vec.dup

Vec.dup makes a new vec containing the same sequence of elements as Vec has.

Example:

:Orig <- ['foo' 'bar' 'baz']
:Dup <- Orig.dup
Orig.set(0 'X')
Dup.set(1 'Y')
stdout.print_line(Orig.repr)  # => ["X" 'bar" "baz"]
stdout.print_line(Dup.repr)   # => ["foo" 'Y" "baz"]

Vec.rev

Vec.rev makes a new vec containing the same elements as Vec has, in the reversed order.

Example:

:Vec <- ['foo' 'bar' 'baz']
stdout.print_line(Vec.rev.repr)  # => ["baz" "bar" "foo"]

Vec.take_front(N)

Vec.take_front makes a new vec containing the first N elements of Vec.

Precondition:

• N must be an int num in the range [0, Vec.size]

Example:

:Slice <- ['foo' 'bar' 'baz' 'qux' 'grault'].take_front(2)
stdout.print_line(Slice.repr)
# => ["foo" "bar"]

Vec.take_back(N)

Vec.take_back makes a new vec containing the last N elements of Vec.

Precondition:

• N must be an int num in the range [0, Vec.size]

Example:

:Slice <- ['foo' 'bar' 'baz' 'qux' 'grault'].take_back(2)
stdout.print_line(Slice.repr)
# => ["qux" "grault"]

Vec.drop_front(N)

Vec.drop_front makes a new vec dropping the first N elements of Vec.

Precondition:

• N must be an int num in the range [0, Vec.size]

Example:

:Slice <- ['foo' 'bar' 'baz' 'qux' 'grault'].drop_front(2)
stdout.print_line(Slice.repr)
# => ["baz" "qux" "grault"]

Vec.drop_back(N)

Vec.drop_back makes a new vec dropping the last N elements of Vec.

Precondition:

• N must be an int num in the range [0, Vec.size]

Example:

:Slice <- ['foo' 'bar' 'baz' 'qux' 'grault'].drop_back(2)
stdout.print_line(Slice.repr)
# => ["foo" "bar" "baz"]

Vec.slice(From_pos To_pos)

Vec.slice makes a new vec containing the slice of Vec in the range [From_pos, To_pos].

Preconditions:

• From_pos and To_pos must be int nums

• 0 <= From_pos <= To_pos <= Vec.size

Example:

:Slice <- ['foo' 'bar' 'baz' 'qux' 'grault'].slice(1 4)
stdout.print_line(Slice.repr)
# => ["bar" "baz" "qux"]

Vec.clear

Vec.clear removes all the elements from Vec.

Example:

:Vec <- ['foo' 'bar' 'baz' 'qux' 'grault']
Vec.clear
stdout.print_line(Vec.repr)
# => []

Vec.clear_slice(From_pos To_pos)

Vec.clear_slice removes the elements from Vec in the range [From_pos, To_pos].

Preconditions:

• From_pos and To_pos must be int nums

• 0 <= From_pos <= To_pos <= Vec.size

Example:

:Vec <- ['foo' 'bar' 'baz' 'qux' 'grault']
Vec.clear_slice(1 4)
stdout.print_line(Vec.repr)
# => ["foo" "grault"]

Vec.push_front(Val)

Vec.push_front adds the Val to the Vec as the first element.

Example:

:Vec <- ['foo' 'bar' 'baz']
Vec.push_front('X')
stdout.print_line(Vec.repr)
# => ["X" "foo" "bar" "baz"]

Vec.push_back(Val)

Vec.push_back adds the Val to the Vec as the last element.

Example:

:Vec <- ['foo' 'bar' 'baz']
Vec.push_back('X')
stdout.print_line(Vec.repr)
# => ["foo" "bar" "baz" "X"]

Vec.push_at(Pos Val)

Vec.push_at adds the Val to the Vec at the specified Val.

Preconditions:

• Pos must be an int num

• 0 <= Pos <= Vec.size

Example:

:Vec <- ['foo' 'bar' 'baz']
Vec.push_at(2 'X')
stdout.print_line(Vec.repr)
# => ["foo" "bar" "X" "baz"]

Vec.push_each_front(Eacher)

Vec.push_each_front adds all the elements of Eacher to the front of the Vec.

Eacher must support each($consume) method, which calls $consume with each element of Eacher.

If Eacher.each passes E(0), E(1), ,,, E(n-1) to $consume for each invocation, and Vec currently contains V(0), V(1), ,,, V(m-1), the elements of Vec will be [E(0) E(1) ,,, E(n-1) V(0) V(1) ,,, V(m-1)] after the invocation of push_each_front.

Example:

:Vec <- ['foo' 'bar' 'baz' 'qux' 'grault']
Vec.push_each_front(['X' 'Y' 'Z'])
stdout.print_line(Vec.repr)
# => ["X" "Y" "Z" "foo" "bar" "baz" "qux" "grault"]

Vec.push_each_back(Eacher)

Vec.push_each_back adds all the elements of Eacher to the back of the Vec.

Eacher must support each($consume) method, which calls $consume with each element of Eacher.

If Eacher.each passes E(0), E(1), ,,, E(n-1) to $consume for each invocation, and Vec currently contains V(0), V(1), ,,, V(m-1), the elements of Vec will be [V(0) V(1) ,,, V(m-1) E(0) E(1) ,,, E(n-1)] after the invocation of push_each_back.

Example:

:Vec <- ['foo' 'bar' 'baz' 'qux' 'grault']
Vec.push_each_back(['X' 'Y' 'Z'])
stdout.print_line(Vec.repr)
# => ["foo" "bar" "baz" "qux" "grault" "X" "Y" "Z"]

Vec.push_each_at(Pos Eacher)

Vec.push_each_at adds all the elements of Eacher to Vec at the specified Pos.

Pos must be an int num in the range [0, Vec.size].

Eacher must support each($consume) method, which calls $consume with each element of Eacher.

If Eacher.each passes E(0), E(1), ,,, E(n-1) to $consume for each invocation, and Vec currently contains V(0), V(1), ,,, V(m-1), the elements of Vec will be [E(0) E(1) ,,, E(Pos-1) V(0) V(1) ,,, V(m-1) E(Pos) ,,, E(n-1)] after the invocation of push_each_at.

Example:

:Vec <- ['foo' 'bar' 'baz' 'qux' 'grault']
Vec.push_each_at(2 ['X' 'Y' 'Z'])
stdout.print_line(Vec.repr)
# => ["foo" "bar" "X" "Y" "Z" "baz" "qux" "grault"]

Vec.pop_front

Vec.pop_front removes the first element from Vec and returns it.

Precondition:

• Vec must not be empty

Example:

:Vec <- ['foo' 'bar' 'baz' 'qux' 'grault']
:Result <- Vec.pop_front
stdout.print_line(Result.repr)  # => "foo"
stdout.print_line(Vec.repr)     # => ["bar" "baz" "qux" "grault"]

Vec.pop_back

Vec.pop_back removes the last element from Vec and returns it.

Precondition:

• Vec must not be empty

Example:

:Vec <- ['foo' 'bar' 'baz' 'qux' 'grault']
:Result <- Vec.pop_back
stdout.print_line(Result.repr)  # => "grault"
stdout.print_line(Vec.repr)     # => ["foo" "bar" "baz" "qux"]

Vec.pop_at(Ind)

Vec.pop_at removes the element of Vec at Ind and returns it.

Precondition:

• Ind must be an int num

• 0 <= Ind < Vec.size

Example:

:Vec <- ['foo' 'bar' 'baz' 'qux' 'grault']
:Result <- Vec.pop_at(1)
stdout.print_line(Result)   # => "bar"
stdout.print_line(Vec.repr) # => ["foo" "baz" "qux" "grault"]

Vec.concat

Vec.concat makes a vec concatenating all the vecs contained in Vec.

Precondition:

• All the elements of Vec must be vecs

Example:

:Vec_of_vecs <- [['foo' 'bar'] ['baz' 'qux'] ['grault']]
:Flat <- Vec_of_vecs.concat
stdout.print_line(Flat.repr)
# => ["foo" "bar" "baz" "qux" "grault"]

Vec.chunk(N)

Vec.chunk returns a vec of vecs, the elements of which are contiguous N elements of Vec.

Precondition:

• N must be a positive int num

• Vec.size % N must be 0

If Vec contains [E(0) E(1) ,,, E(N-1) E(N) E(N+1) ,,, E(N+(N-1)) ,,, E(m*N) E(m*N+1) ,,, E(m*N+(N-1))], Vec.chunk returns [[E(0) E(1) ,,, E(N-1)] [E(N) E(N+1) ,,, E(N+(N-1))] ,,, [E(m*N) E(m*N+1) ,,, E(m*N+(N-1))]].

Example:

:Vec <- ['foo' 'bar' 'baz' 'qux' 'grault' 'fred']
:Chunks <- Vec.chunk(2)
stdout.print_line(Chunks.repr)
# => [["foo" "bar"] ["baz" "qux"] ["grault" "fred"]]

Vec.just

Vec.just returns the element of the single element Vec.

Precondition:

• Vec.size must be 1

Example:

:Vec <- ['foo']
:Result <- Vec.just
stdout.print_line(Result.repr)  # => "foo"

Vec.just_or($on_empty)

Vec.just_or returns the element of the single element Vec, or tail-calls $on_empty with no args if Vec is empty.

Precondition:

• Vec.size must be 0 or 1

Example:

:inspect <- {(:Vec)
  :Result = Vec.just_or{ 'empty' }
  stdout.print_line(Result.repr)
}
inspect(['foo'])  # => "foo"
inspect([])       # => "empty"

The typical usage of this method is providing the default result for methods like Vec.search, which returns a single-element vec or an empty vec.

Example:

:with_border <- {(:Vec)
  :Pos = Vec.search(0){(:E) E >= 10 }.just_or{ Vec.size }
  Vec.take_front(Pos) + ['<-less than 10'] + Vec.drop_front(Pos)
}

stdout.print_line(with_border([1 2 3 5 8 13 21]).repr)
# => [1 2 3 5 8 "<- less than 10" 13 21]

stdout.print_line(with_border([1 2 3]).repr)
# => [1 2 3 "<- less than 10"]

Vec.for_maybe($on_just $on_empty)

Vec.for_maybe branches on the maybe_vec whether it has a single element, or it has no element.

Precondition:

• Vec.size must be 0 or 1

If Vec has 1 element, .for_maybe tail-calls $on_just with the element.

If Vec has 0 element, .for_maybe tail-calls $on_empty with no args.

Example:

:print_sum <- {(:Vec)
  Vec.reduce{ \0 + \1 }.for_maybe(
    {(:Sum) stdout.print_line(Sum.repr) }
    {() stdout.print_line('Vec is empty') }
  )
}

print_sum([1 2 3 4 5])  # => 15
print_sum([])  # => Vec is empty

Vec.each($on_elem)

Vec.each calls $on_elem with each element of Vec as an arg, in the ascending order of the indices.

If Vec is nonempty, Vec.each tail-calls $on_elem for the last element.

Example:

:Vec <- ['foo' 'bar' 'baz']
Vec.each{(:E)
  stdout.print_line(E.repr)
}
# Output:
#   "foo"
#   "bar"
#   "baz"

Vec.map($trans)

Vec.map makes a vec the elements of which is transformed from the elements of Vec by $trans.

If Vec contains [E(0) E(1) ,,, E(n-1)], the elements of the result vec will be [trans(E(0)) trans(E(1)) ,,, trans(E(n-1))].

Example:

:Vec <- ['foo' 'bar' 'baz']
:Mapped <- Vec.map{(:E)
  '<<{}>>'.format(E)
}
stdout.print_line(Mapped.repr)  # => ["<<foo>>" "<<bar>>" "<<baz>>"]

Vec.concat_map($trans_to_vec)

Vec.concat_map maps the elements then concats.

Invoking Vec.concat_map($trans_to_vec) is equivalent to invoking Vec.map($trans_to_vec).concat.

Example:

# extracts runes from the strs
:to_runes <- {(:Strs)
  Strs.concat_map{(:S)
    S.runes
  }
}
:Runes <- to_runes(['foo' 'bar' 'baz'])
stdout.print_line(Runes.repr)
# => [102 111 111 98 97 114 98 97 122]

Vec.filter($match?)

Vec.filter makes a vec containing all the elements that satisfy the predicate $match?.

$match? is expected to take one argument, which is an element of Vec, and return true or false.

If $match? returns true for an element, the element is contained in the result. If $match? returns false for an element, the element is not contained in the result.

Example:

:Nums <- [1 2 3 5 8 13 21 34 55 89]
:Evens <- Nums.filter{(:N)
  N % 2 == 0
}
stdout.print_line(Evens.repr) # => [2 8 34]

Vec.count($match?)

Vec.count returns the number of elements of Vec which satisfies $match?.

$match? is expected to take one argument, which is an element of Vec, and return true or false.

If $match? returns true for an element, the element is counted. If $match? returns false for an element, the element is not counted.

Example:

:Nums <- [1 2 3 5 8 13 21 34 55 89]
:Even_count <- Nums.count{(:N)
  N % 2 == 0
}
stdout.print_line(Even_count.repr) # => 3

Vec.fold(Init $combine)

Vec.fold accumulates elements seeded by Init.

If Vec contains elements [E(0) E(1) ,,, E(n-1)], Vec.fold returns combine(combine(,,, combine(combine(Init E(0)) E(1)) ,,,) E(n-1)).

Example:

:to_quote_line <- {(:Words)
  Words.fold('>'){(:Accum :Word)
    Accum + ' ' + Word
  }
}
:Quote <- to_quote_line(['foo' 'bar' 'baz'])
stdout.print_line(Quote.repr) # => "> foo bar baz"

Vec.reduce($combine)

Vec.reduce accumulates elements of Vec mutually, then returns a maybe_vec.

If Vec is empty, Vec.reduce returns an empty vec [].

If Vec has only one element E, Vec.reduce returns a single-element vec [E].

If Vec has two or more elements [E(0) E(1) E(2) ,,, E(n-1)], Vec.reduce returns a single-element vec [combine(combine(,,, combine(combine(E(0) E(1)) (E2)) ,,,) E(n-1))].

Example:

:separate_by_commas <- {(:Args)
  Args.reduce{(:Accum :Arg)
    Accum + ', ' + Arg
  }.just_or{ '' }
}

stdout.print_line(separate_by_commas(['foo' 'bar' 'baz']).repr)
# => "foo, bar, baz"

stdout.print_line(separate_by_commas([]).repr)
# => ""

Vec.scan(Init $combine)

Vec.scan returns a vec of accumulated vals, seeded by Init.

If Vec contains [E(1) E(2) ,,, E(n-1)], the result will contain [R(0) R(1) R(2) ,,, R(n-1)], where:

• R(0) is Init

• For i>=1, R(i) = combine((R(i)-1) E(i))

Example:

:Scanned <- [1 2 3 4 5].scan(10){(:N1 :N2)
  N1 + N2
}
stdout.print_line(Scanned.repr)
# => [10 11 13 16 20 25]

Note that the size of the result is Vec.size + 1.

Vec.scan_inside($combine)

Vec.scan_inside returns a vec of mutually accumulated vals.

If Vec is empty, Vec.scan_inside returns an empty vec [].

If Vec is nonempty, and contains [E(0) E(1) ,,, E(n-1)], Vec.scan_inside returns a vec [R(0) R(1) ,,, R(n-1)], where:

• R(0) is E(0)

• For i>=1, R(i) = combine(R(i-1) E(i))

Example:

:Scanned <- [1 2 3 4 5].scan_inside{(:N1 :N2)
  N1 + N2
}
stdout.print_line(Scanned.repr)
# => [1 3 6 10 15]

Note that the size of the result is equal to Vec.size.

Vec.take_while($match?)

Vec.take_while returns a vec of the longest initial prefix of Vec the elements of which satisfy $match?.

Example:

:Nums <- [1 (-2) 3 (-4) 5 (-6) 7 (-8)]
:Prefix <- Nums.take_while{(:N)
  N < 5
}
stdout.print_line(Prefix.repr)
# => [1 (-2) 3 (-4)]

Vec.drop_while($match?)

Vec.drop_while returns a vec after the longest initial prefix of Vec the elements of which satisfy $match?.

Example:

:Nums <- [1 (-2) 3 (-4) 5 (-6) 7 (-8)]
:Suffix <- Nums.drop_while{(:N)
  N < 5
}
stdout.print_line(Suffix.repr)
# => [5 (-6) 7 (-8)]

Vec.for_all?($match?)

Vec.for_all? returns whether all the elements of Vec satisfy $match?.

Example:

:all_even? <- {(:Nums)
  Nums.for_all?{(:N)
    N % 2 == 0
  }
}
stdout.print_line(all_even?([0 2 4]).repr)  # => true
stdout.print_line(all_even?([6 7 9]).repr)  # => false
stdout.print_line(all_even?([1 3 5]).repr)  # => false

Vec.for_any?($match?)

Vec.for_any? returns whether at least one of the elements of Vec satisfies $match?.

Example:

:any_even? <- {(:Nums)
  Nums.for_any?{(:N)
    N % 2 == 0
  }
}
stdout.print_line(any_even?([0 2 4]).repr)  # => true
stdout.print_line(any_even?([6 7 9]).repr)  # => true
stdout.print_line(any_even?([1 3 5]).repr)  # => false

Vec.have?(Target)

Vec.have? returns whether at least one element satisfies Target.op_eq method.

Calling Vec.have?(Target) is equivalent to calling Vec.for_any?{(:E) Target == E }.

Example:

stdout.print_line([1 3 5].have?(3).repr)  # => true
stdout.print_line([2 4 6].have?(3).repr)  # => false

TODO the implementation is calling E == Target, instead of Target == E. Fix it

Vec.have_all?(For_aller)

Vec.have_all? returns whether Vec has all the elements of For_aller.

Preconditions:

• For_aller must support .for_all?($match?)

• All the elements of For_aller must support op_eq(Arg) method with elements of Vec.

Calling Vec.have_all?(For_aller) is equivalent to calling For_aller.for_all?{(:T) Vec.have?(T) }.

Example:

:Vec <- [2 4 6 8]
stdout.print_line(Vec.have_all?([2 4]).repr)  # => true
stdout.print_line(Vec.have_all?([6 7]).repr)  # => false

Vec.have_all? can take arguments other than vecs, provided the argument supports for_all? method. Example:

:FLAT_SET.require_from('kink/container/')
:Vec <- [2 4 6 8]
stdout.print_line(Vec.have_all?(FLAT_SET.of(2 4)).repr) # => true
stdout.print_line(Vec.have_all?(FLAT_SET.of(6 7)).repr) # => false

Vec.have_any?(For_anyer)

Vec.have_any? returns whether Vec has any element of For_anyer.

Preconditions:

• For_anyer must support .for_any?($match?)

• All the elements of For_anyer must support .op_eq(Arg) method with elements of Vec.

Calling Vec.have_any?(For_aller) is equivalent to calling For_anyer.for_any?{(:T) Vec.have?(T) }.

Example:

:Vec <- [2 4 6 8]
stdout.print_line(Vec.have_any?([2 4]).repr)    # => true
stdout.print_line(Vec.have_any?([6 7]).repr)    # => true
stdout.print_line(Vec.have_any?([10 20]).repr)  # => false

Vec.have_any? can take arguments other than vecs, provided the argument supports for_any? method. Example:

:FLAT_SET.require_from('kink/container/')
:Vec <- [2 4 6 8]
stdout.print_line(Vec.have_any?(FLAT_SET.of(2 4)).repr)   # => true
stdout.print_line(Vec.have_any?(FLAT_SET.of(6 7)).repr)   # => true
stdout.print_line(Vec.have_any?(FLAT_SET.of(10 20)).repr) # => false

Vec.search(From_pos $match?)

Vec.search tries to find the first index at or after From_pos, where the element satisfies $match?.

• From_pos must be an int num

• 0 <= From_pos <= Vec.size

If such an index is found, Vec.search returns a single-element vec [Ind], where Ind is the index.

If such an index is not found, Vec.search returns an empty vec [].

Example:

:output_three_letter_words <- {(:Words)
  :loop <- {(:Pos)
    (Pos <= Words.size).if_true{
      Words.search(Pos){(:W)
        W.size == 3
      }
      .each{(:Ind)
        stdout.print_line('#{}: {}'.format(Ind Words.get(Ind)))
        loop(Ind + 1)
      }
    }
  }
  loop(0)
}
output_three_letter_words(['foo' 'aoxomoxoa' 'bar' 'grault' 'baz'])
# Output:
#   #0: foo
#   #2: bar
#   #4: baz

The program above is equivalent to the following:

:output_three_letter_words <- {(:Words)
  Words.size.times.filter{(:I)
    Words.get(I).size == 3
  }
  .each{(:Ind)
    stdout.print_line('#{}: {}'.format(Ind Words.get(Ind)))
  }
}
output_three_letter_words(['foo' 'aoxomoxoa' 'bar' 'grault' 'baz'])
# Output:
#   #0: foo
#   #2: bar
#   #4: baz

Vec.sort(...[$precede?])

Vec.sort returns a vec the elements of which are copied from Vec and sorted in the ascending order specified by $precede?.

$precede? must take two args which are elements of Vec, and must suffice the following conditions:

• $precede? must return true or false

• If precede?(X Y) returns true, precede?(Y X) must return false

$precede? can be regarded as a generalized version of “<=” operator.

If $precede? argument is omitted, Vec.sort uses {(:X :Y) X < Y } as the default val.

Vec.sort performs a stable sort. In the result vec, the following conditions are met.

• All the elements of Vec appears in the result vec the same number of times as in Vec.

• Sorted: If precede?(E1 E2) returns true, where E1 and E2 are elements of Vec at different indices, E1 appears before E2 in the result vec.

• Stable: If both precede?(E1 E2) and precede?(E2 E1) return false, where E1 and E2 are elements of Vec at different indices and E1 appears before E2 in Vec, E1 appears before E2 also in the result vec.

Example:

:Vec <- ['Hakuho' 'Asashoryu' 'Takanohana' 'Chiyonofuji' 'Kitanoumi' 'Taiho' 'Futabayama']

:Lex_sort <- Vec.sort
stdout.print_line(Lex_sort.repr)
# => ["Asashoryu" "Chiyonofuji" "Futabayama" "Hakuho" "Kitanoumi" "Taiho" "Takanohana"]

:Size_sort <- Vec.sort{(:X :Y) X.size < Y.size }
stdout.print_line(Size_sort.repr)
# => ["Taiho" "Hakuho" "Asashoryu" "Kitanoumi" "Takanohana" "Futabayama" "Chiyonofuji"]

Vec.iter

Vec.iter makes an iter for the elements of Vec.

Example:

['foo' 'bar' 'baz' 'qux' 'grault'].iter.each{(:S)
  stdout.print_line(S.repr)
}
# Output:
#   "foo"
#   "bar"
#   "baz"
#   "qux"
#   "grault"

Vec.iter_from(From_pos)

Vec.iter_from makes an iter for the elements of Vec from From_pos.

Precondition:

• From_pos must be an int num

• 0 <= From_pos <= Vec.size

Example:

['foo' 'bar' 'baz' 'qux' 'grault'].iter_from(2).each{(:S)
  stdout.print_line(S.repr)
}
# Output:
#   "baz"
#   "qux"
#   "grault"

Vec.op_add(Arg_vec)

Vec.op_add makes a vec containing all the elements of Vec in the front, and all the elements of Arg_vec in the back.

Arg_vec must be a vec.

Example:

stdout.print_line((['foo' 'bar'] + ['baz' 'qux']).repr)
# => ["foo" "bar" "baz" "qux"]

Vec.op_mul(N)

Vec.op_mul makes a vec containing the elements of Vec repeating N times.

Preconditions:

• N must be an int num

• N >= 0

Example:

stdout.print_line((['foo' 'bar'] * 3).repr)
# => ["foo" "bar" "foo" "bar" "foo" "bar"]

Vec.op_eq(Arg_vec) Vec.op_ne(Arg_vec)

Vec.op_eq and op_ne return whether or not two vecs contain equal elements.

Preconditions:

• Arg_vec must be a vec

Two vecs are equal if:

1) Vec.size == Arg_vec.size

2) For all i in [0, Vec.size), Vec.get(i) == Arg_vec.get(i)

The conditions are tested in the numbered order, and from the smallest i to the biggest i. If a test returns false, subsequent tests are not evaluated and two vecs are considered not equal.

Example:

:CONTROL.require_from('kink/')

:test_equality <- {(:Vec :Arg_vec)
  CONTROL.try(
    { Vec == Arg_vec }
    {(:Result) stdout.print_line('op_eq={}'.format(Result.repr)) }
    {(:Msg :Traces)
      stdout.print_line('op_eq: exception: {}'.format(Msg))
    }
  )
  CONTROL.try(
    { Vec != Arg_vec }
    {(:Result) stdout.print_line('op_ne={}'.format(Result.repr)) }
    {(:Msg :Traces)
      stdout.print_line('op_ne: exception: {}'.format(Msg))
    }
  )
}

# equal
test_equality(['foo' 42] ['foo' 42])
# Output:
#   op_eq=true
#   op_ne=false

# not equal because sizes differ
test_equality(['foo' 42] ['foo' 42 'bar'])
# Output:
#   op_eq=false
#   op_ne=true

# not equal because the first elemenets differ
test_equality(['foo' 42] ['bar' 42])
# Output:
#   op_eq=false
#   op_ne=true

# not equal because the first elemenets differ;
# the second elements are not tested
test_equality(['foo' 42] ['bar' '***'])
# Output:
#   op_eq=false
#   op_ne=true

test_equality(['foo' 42] ['foo' '***'])
# Output:
#   op_eq: exception: Num.op_eq: required num as \0, but got "***"
#   op_ne: exception: Num.op_ne: required num as \0, but got "***"

Vec.op_lt(Arg_vec) Vec.op_le(Arg_vec) Vec.op_gt(Arg_vec) Vec.op_ge(Arg_vec)

Vec.op_le, op_le, op_gt and op_ge compare elements of two vecs.

The methods use the natural ordering defined by <, <=, > and >= operators to compare elements.

Vec is less than Arg_vec when:

1) There is a nonnegative int num k (k < Vec.size and k < Arg_vec.size), such that for all i (0 <= i < k) Vec.get(i) is equal to Arg_vec.get(i), and Vec.get(k) is less than Arg_vec.get(k); or

2) Vec.size < Arg_vec.size and for all i (0 <= i < Vec.size), Vec.get(i) is equal to Arg_vec.get(i).

Tests are done from the smallest index to the biggest index. If it can be asserted that Vec is less than Arg_vec or Arg_vec is less than Vec after comparing elements at an index, the subsequent tests are not evaluated.

Example:

:compare <- {(:Vec :Arg_vec)
  [:Lt? :Le? :Gt? :Ge?] = [
    Vec < Arg_vec
    Vec <= Arg_vec
    Vec > Arg_vec
    Vec >= Arg_vec
  ]
  stdout.print_line(
    'Lt?={} Le?={} Gt?={} Ge?={}'.format(Lt?.repr Le?.repr Gt?.repr Ge?.repr))
}

compare(['A' 42] ['A' 42])
# => Lt?=false Le?=true Gt?=false Ge?=true

compare(['A' 42] ['A' 42 'foo'])
# => Lt?=true Le?=true Gt?=false Ge?=false

compare(['A' 42] ['A'])
# => Lt?=false Le?=false Gt?=true Ge?=true

compare(['A' 42] ['B' 42])
# => Lt?=true Le?=true Gt?=false Ge?=false

compare(['A' 42] ['A' 84])
# => Lt?=true Le?=true Gt?=false Ge?=false

Vec.op_store(Rhs_vec)

Vec.op_store performs multiple assignments, using the elements of Vec as left-hand-side vals, and the elements of Rhs_vec as right-hand-side vals.

Rhs_vec must be a vec.

There are three types of left-hand-side vals:

• plain_param: which has op_store method; see kink/param/PLAIN_PARAM mod.

• opt_param: which has pass_arg and pass_nothing methods; see kink/param/OPT_PARAM mod.

• rest_param: which has pass_rest method: see kink/param/REST_PARAM mod.

Confirugation of left-hand-side vals:

• There can be 0 or more plain_param vals in Vec.

• There can be 0 or more opt_param vals in Vec, after plain_param vals.

• There can be 0 or 1 rest_param val in Vec, after plain_param and opt_param vals.

So there are two cases for the configuration of left-hand-side vals:

A) The elements of Vec are [P(0) P(1) ,,, P(m-1) O(0) O(1) ,,, O(n-1)], where m is the number of plain_param vals, P(i) (0 <= i < m) is a plain_param val, n is the number of opt_param vals, and O(i) (0 <= i < n) is an opt_param val. In that case, the range of valid numbers of right-hand-side vals is [m, m+n].

B) The elements of Vec are [P(0) P(1) ,,, P(m-1) O(0) O(1) ,,, O(n-1) R], where m is the number of plain_param vals, P(i) (0 <= i < m) is a plain_param val, n is the number of opt_param vals, O(i) (0 <= i < n) is an opt_param val, and R is a rest_param val. In that case, the range of valid numbers of right-hand-side vals is [m, ∞].

If the number of elements of Rhs_vec is not valid, Vec.op_store raises an exception.

If the number of elements of Rhs_vec is valid, in the case A,

• Vec.op_store calls P(i).op_store(Rhs_vec.get(i)) for each int num i (0 <= i < m).

• Vec.op_store calls O(i).pass_arg(Rhs_vec.get(m+i)) for each int num i (0 <= i < Rhs_vec.size-m).

• Vec.op_store calls O(i).pass_nothing for each int num i (Rhs_vec.size-m <= i < n).

In the case B, and the number of right-hand-side vals is less than or equal to m+n,

• Vec.op_store calls P(i).op_store(Rhs_vec.get(i)) for each int num i (0 <= i < m).

• Vec.op_store calls O(i).pass_arg(Rhs_vec.get(m+i)) for each int num i (0 <= i < Rhs_vec.size-m).

• Vec.op_store calls O(i).pass_nothing for each int num i (Rhs_vec.size-m <= i < n).

• Vec.op_store calls R.pass_rest([]).

In the case B, and the number of right-hand-side vals is greater than m+n,

• Vec.op_store calls P(i).op_store(Rhs_vec.get(i)) for each int num i (0 <= i < m).

• Vec.op_store calls O(i).pass_arg(Rhs_vec.get(m+i)) for each int num i (0 <= i < n).

• Vec.op_store calls R.pass_rest(Rhs_vec.drop_front(m+n)).

Example:

:CONTROL.require_from('kink/')

[:X :Y] <- ['x' 'y']
stdout.print_line('X={} Y={}'.format(X.repr Y.repr))
# => X="x" Y="y"

[:X :Y :Z.opt :W.opt] <- ['x' 'y']
stdout.print_line('X={} Y={} Z={} W={}'.format(X.repr Y.repr Z.repr W.repr))
# => X="x" Y="y Z=[] W=[]"

[:X :Y :Z.opt :W.opt] <- ['x' 'y' 'z']
stdout.print_line('X={} Y={} Z={} W={}'.format(X.repr Y.repr Z.repr W.repr))
# => X="x" Y="y Z=["z"] W=[]"

[:X :Y :Z.opt :W.opt] <- ['x' 'y' 'z' 'w']
stdout.print_line('X={} Y={} Z={} W={}'.format(X.repr Y.repr Z.repr W.repr))
# => X="x" Y="y Z=["z"] W=["w"]"

[:X :Y :R.rest] <- ['x' 'y']
stdout.print_line('X={} Y={} R={}'.format(X.repr Y.repr R.repr))
# => X="x" Y="y" R=[]

[:X :Y :R.rest] <- ['x' 'y' 'r1' 'r2']
stdout.print_line('X={} Y={} R={}'.format(X.repr Y.repr R.repr))
# => X="x" Y="y" R=["r1" "r2"]

[:X :Y :Z.opt :W.opt :R.rest] <- ['x' 'y']
stdout.print_line('X={} Y={} Z={} W={} R={}'.format(X.repr Y.repr Z.repr W.repr R.repr))
# => X="x" Y="y" Z=[] W=[] R=[]

[:X :Y :Z.opt :W.opt :R.rest] <- ['x' 'y' 'z']
stdout.print_line('X={} Y={} Z={} W={} R={}'.format(X.repr Y.repr Z.repr W.repr R.repr))
# => X="x" Y="y" Z=["z"] W=[] R=[]

[:X :Y :Z.opt :W.opt :R.rest] <- ['x' 'y' 'z' 'w']
stdout.print_line('X={} Y={} Z={} W={} R={}'.format(X.repr Y.repr Z.repr W.repr R.repr))
# => X="x" Y="y" Z=["z"] W=["w"] R=[]

[:X :Y :Z.opt :W.opt :R.rest] <- ['x' 'y' 'z' 'w' 'r1' 'r2']
stdout.print_line('X={} Y={} Z={} W={} R={}'.format(X.repr Y.repr Z.repr W.repr R.repr))
# => X="x" Y="y" Z=["z"] W=["w"] R=["r1" "r2"]

# Invalid numbers of right-hand-side vals:
CONTROL.try(
  { [:X :Y] <- [1 2 3] }
  { raise('must not reach here') }
  {(:Msg :Traces)
    stdout.print_line('exception: {}'.format(Msg))
  }
)
# => exception: too many args: for [:X :Y], got [1 2 3]

CONTROL.try(
  { [:X :Y] <- [1] }
  { raise('must not reach here') }
  {(:Msg :Traces)
    stdout.print_line('exception: {}'.format(Msg))
  }
)
# => exception: too few args: for [:X :Y], got [1]

Note: formal arguments in function bodies are translated to invocation of Vec.op_store. See “Language specification” → “Semantics” chapter. Two definitions of min are equivalent in the following example:

:min <- {(:X :Y)
  (X <= Y).if_else({ X } { Y })
}

:min <- {
  [:X :Y] <- \args
  (X <= Y).if_else({ X } { Y })
}

Note: in most cases it is better to use a let clause for multiple assignments for local vars.

:calc_start_end <- {
  # do some complicated calculation
  # ...
  [10 20]
}

:do_something <- {
  [:Start :End] = calc_start_end
  stdout.print_line('Start={} End={}'.format(Start End))
}
do_something
# => Start=10 End=20

do_something is translated as follows:

:do_something <- {
  {([:Start :End])
    stdout.print_line('Start={} End={}'.format(Start End))
  }!!(calc_start_end)
}

See “Language specification” → “Semantics” chapter also for let clauses.

Vec.repr

Vec.repr returns a str representation of Vec such as '["foo" 42]'.

3.23.2. VEC.vec?(Val)

VEC.vec? returns whether Val is a vec val.

3.23.3. VEC.of_each(Eacher)

VEC.of_each makes a vec including the elements of Eacher.

The Eacher must support .each($consume) method like vecs and iters.

Example:

:VEC.require_from('kink/')
:FLAT_SET.require_from('kink/container/')
:Set <- FLAT_SET.of('foo' 'bar' 'baz')
stdout.print_line(VEC.of_each(Set).repr)
# => ["bar" "baz" "foo"]