Fuzion Logo
fuzion-lang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

container/Typed_Sequence.fz


# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
#  Tokiwa Software GmbH, Germany
#
#  Source code of Fuzion standard library feature Typed_Sequence
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# Typed_Sequence -- ancestor for features representing sequence of typed values
#
# Unlike `Sequence`, which contains values of all the same type, a `Typed_Sequence`
# contains values of different types.  This is similar to `Sequence Any`, only that
# values are not forced to be boxed into references.
#
# Actual implementations of this must provide an implementation of abstract feature
# `typed_foldf`.
#
# The desired way to use this feature is via calls to `typed_foldf` since this will
# avoid the creation of boxed `Typed_Value` instances.
#
# `Typed_Sequence` inherits from `Sequence Typed_Value` such that all the power of
# `Sequence` is available here, but at the cost of boxing into `Typed_Value`
# references values.
#
public Typed_Sequence ref : Sequence container.Typed_Value is


  # create a list from this Typed_Sequence.
  #
  # Note that this creates boxed ref instances of `Typed_Value`.  The preferred
  # means to acces the values is via a call to `typed_foldf`.
  #
  public redef as_list list container.Typed_Value =>

    as_reverse_list : /* NYI: BUG: #5712: explicit `container.` required as workaround for this bug */
                      container.typed_applicator (list container.Typed_Value) is

      public redef apply(A type, e (list container.Typed_Value), v A) list container.Typed_Value
      =>
        container.typed_value v : e

    typed_foldf nil as_reverse_list .reverse_list


  # is this sequence known to be finite?  For infinite sequences, features like
  # count diverge.
  #
  # TRUE  = known finite
  # FALSE = known infinite
  # nil   = unknown
  #
  public redef finite trit => trit.yes


  # count the number of elements in this Typed_Sequence.
  #
  # This is redefined and implemented using `typed_foldf` to avoid creation of
  # boxed `Typed_Value`s.
  #
  public redef count i32
  =>
    count_elements : /* NYI: BUG: #5712: explicit `container.` required as workaround for this bug */
                     container.typed_applicator i32 is
      public redef apply(A type, e i32, v A) i32 => e + 1

    typed_foldf 0 count_elements


  # fold the elements of this `Typed_Sequence` using the given `typed_applicator`
  # and initial value.
  #
  # In case this `Typed_Sequence` is empty, the result is `e`.
  #
  public typed_foldf(E type, A type : container.typed_applicator E, e E, a A) E
  =>
    abstract


  # zip the elements of this `Typed_Sequence` using the given `typed_zipper`
  # and initial value.
  #
  # In case this `Typed_Sequence` is empty, the result is `e`.
  #
  public typed_zip_and_fold(E type, Z type : typed_zipper E, b Typed_Sequence.this, e E, z Z) E
  =>
    abstract


# typed_fold -- convenience feature to fold the elements of a `Typed_Sequence`.
#
# ex:
#
#     # print all value arguments into numbered lines, return next line number
#     #
#     printn(A type ..., a A...) : container.typed_fold 1 a
#     =>
#       public redef apply(T type, n i32, v T) i32
#       =>
#         say "$n: $v"
#         n + 1
#
#       res    # field `res` will receive the result of last `apply`
#
public typed_fold(E type, e E, s container.Typed_Sequence) : container.typed_applicator E is

  # the result of the fold
  #
  # the fold is done eagerly to ensure any side-effects will be performed even if `res` is
  # never read.
  #
  public res E := s.typed_foldf e typed_fold.this


# variadic -- convenience feature to fold the elements of a `Typed_Sequence`.
#
# ex:
#
#     # print all value arguments into numbered lines, return next line number
#     #
#     printn(A type ..., a A...) : container.variadic i32
#     =>
#       public redef apply(T type, n i32, v T) i32
#       =>
#         say "$n: $v"
#         n + 1
#
#       process 1 a    # precess returns result of last `apply`
#
# NYI: CLEANUP: #6896 This is somewhat redundant with `typed_fold`, we should
# decide on only one of these variants or find a different solution now that
# lambdas for `typed_applicator` are supported.  We should compare example and
# the usability of different APis.
#
public variadic(E type) : container.typed_applicator E is

  # the result of the fold
  #
  public process(e E, s container.Typed_Sequence) E
  =>
    s.typed_foldf e variadic.this


# a function that operates on a value of type that is given by the caller
#
# This is used as an argument to `Typed_Sequence.typed_foldf` to process the typed
# values.
#
public typed_applicator(E type) is


  # Apply an operation on a value v of type T using the cumulative value
  # `e`, and type type / value pair `T`/`v`,  create a new value of type
  # `B` and return it
  #
  # ex:
  #
  # to concatenate the String representation of all values, use
  #
  #     my_concat : container.typed_applicator String is
  #
  #       public redef apply(T type, e String, v T) String
  #       =>
  #         e + $v
  #
  public apply(T type, e E, v T) E
    : fuzion.lambda_target
  =>
    abstract


# a function that operates on two values of type that is given by the caller.
#
# This is used as an argument to `Typed_Sequence.typed_zipper` to process two
# equals streams of typed values.
#
public typed_zipper(# the result type of two values that were zipped
                    #
                    E type
                   ) is


  # Zip values `v` and `w` of type T,  create a new value of type
  # `B` and return it
  #
  # ex:
  #
  # to check if all values are equal, use
  #
  #     my_zip : container.typed_zipper bool is
  #
  #       public redef apply(T type, e bool, v, w T) bool
  #       =>
  #         if T : property.equatable then
  #           b && v = w
  #         else
  #           panic "$T is not `property.equatable`!"
  #
  public apply(T type,
               e E,
               v, w T) E
  =>
    abstract


# Typed_Value -- a ref type to hold a value of an arbitrary type
#
# The value can be extracted by a call to `Typed_Value.apply_to`
#
public Typed_Value ref is


  # Feed this value's type, the cumulative value `e` and this value itself into
  # `a.apply` and return the resulting cumulative value.
  #
  public apply_to(E type, A type: container.typed_applicator E, e E, a A) E
  =>
    abstract


# typed_value -- value type heir of `Typed_Value`.
#
# This must be a heir of `Typed_Value` since we need to be able to
# have different actual type parameters and still create ref values
# of all the same type `Typed_Value`.
#
public typed_value(# the type
                   T type,

                   # the value
                   v T)
  : Typed_Value is

  # apply `a` to `T` `e` `v`
  #
  public redef apply_to(E type, A type: container.typed_applicator E, e E, a A) E
  =>
    a.apply T e v


  # create a String of the form `"<type> <value>"` where `<type>`
  # is the name of the type, enclosed by `(`/`)` in case it contains
  # spaces.
  #
  # Examples:
  #
  #     i32 42
  #     (array i32) [1, 2, 3]
  #     String Hello World!
  #
  public redef as_string String
  =>
    t := T.name
    if t.find " " ??
      "($t) $v"
    else
      "$t $v"


# Types -- sequence of `Type` that may be processed without being boxed
#
# This inherits from `Sequence Type` for convenience of all the
# infrastructure provided by `Sequence`.  Nevertheless, the
# prefererd use is via calls to `Types.type_foldf` only since
# these calls do not require boxing of the types and permit
# code specialization of the actual types.
#
# This is a parent of `Open_Types`, which itself is the parent of
# the types generated for calls to open type parameters.
#
public Types ref : Sequence Type is


  # create a list from this `Types` instance.
  #
  # Note that this creates boxed ref instances of `Type`.  The preferred
  # means to acces the values is via a call to `type_foldf`.
  #
  public redef as_list list Type =>

    as_reverse_list : container.type_applicator (list Type) is

      public redef apply(A type, e (list Type)) list Type
      =>
        list (id Type A) e

    type_foldf nil as_reverse_list .reverse_list


  # is this sequence known to be finite?  For infinite sequences, features like
  # count diverge.
  #
  # TRUE  = known finite
  # FALSE = known infinite
  # nil   = unknown
  #
  public redef finite trit => trit.yes


  # count the number of elements in this `Types` instance.
  #
  # This is redefined and implemented using `type_foldf` to avoid creation of
  # boxed `Type`s.
  #
  public redef count i32
  =>
    count_elements : container.type_applicator i32 is
      public redef apply(A type, e i32) i32 => e + 1

    type_foldf 0 count_elements


  # fold the elements of this `Types` instance using the given `type_applicator`
  # and initial value.
  #
  # In case this `Types` instance is empty, the result is `e`.
  #
  public type_foldf(E type, A type : type_applicator E, e E, a A) E
  =>
    abstract


# a function that operates on a type that is given by the caller
#
# This is used as an argument to `Types.type_foldf` to process the types.
#
public type_applicator(E type) is


  # Apply an operation on a type `T` using the cumulative value
  # `e`,  create a new value of type `E` and return it
  #
  # ex:
  #
  # to concatenate the String representation of all types, use
  #
  #     my_concat : container.type_applicator String is
  #
  #       public redef apply(T type, e String) String
  #       =>
  #         e + $T
  #
  public apply(T type, e E) E : fuzion.lambda_target
  =>
    abstract

last changed: 2026-04-21