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

numOption.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 numOption
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# numOption -- optional numeric values
#
# This is a pseudo-numeric type that handles one additional
# value: nil.  Any operation on nil will result in nil for a
# numeric result or false for a boolean result.
#
numOption<T: numeric<T>> :
  choice<T, nil>,
  monad<T, numOption<T>>
is

  # Does this option contain a value of type T?
  #
  exists => numOption.this ? T   => true
                           | nil => false


  # short-hand postfix operator for 'exists'
  #
  postfix ?? => exists


  # Does this option contain no value of type T?
  #
  isNil => !exists


  # short-hand postfix operator for 'isNil'
  #
  postfix !! => isNil


  # value of an option that is known to contain a value
  #
  # this can only be called in cases where it is known for sure that this option
  # is not nil.  A runtime error will be created otherwise.
  #
  val T
    pre
      safety: numOption.this??
  is
    numOption.this ? v T => v
                   | nil => fuzion.std.panic "numOption.val called on nil"


  # monadic operator
  redef infix >>= (f T -> numOption<T>) => numOption.this.bind<T>(f)


  # monadic operator
  #
  # Same as non-generic >>=, but also maps to a different type B.
  #
  bind <B> (f T -> numOption<B>) numOption<B> is
    numOption.this ? v T => f(v)
                   | nil => nil


  # monadic operator for bool result, false for nil
  infix >>? (f T -> bool) =>
    numOption.this ? v T => f(v)
                   | nil => false


  # basic prefix operations
  prefix +? numOption<T> is numOption.this >>= fun(v T) numOption<T> is +v
  prefix -? numOption<T> is numOption.this >>= fun(v T) numOption<T> is -?v

  # basic infix operations
  infix +? (other numOption<T>) numOption<T> is numOption.this >>= fun(v T) => other >>= fun(w T) => v +? w
  infix -? (other numOption<T>) numOption<T> is numOption.this >>= fun(v T) => other >>= fun(w T) => v -? w
  infix *? (other numOption<T>) numOption<T> is numOption.this >>= fun(v T) => other >>= fun(w T) => v *? w
  infix **?(other numOption<T>) numOption<T> is numOption.this >>= fun(v T) => other >>= fun(w T) => v **? w
  infix /? (other numOption<T>) numOption<T>
    pre
      safety: !other.isZero
  is
    numOption.this >>= fun(v T) numOption<T> is other >>= fun(w T) numOption<T> is v / w

  infix %? (other numOption<T>) numOption<T>
    pre
      safety: !other.isZero
  is
    numOption.this >>= fun(v T) numOption<T> is other >>= fun(w T) numOption<T> is v % w

  # comparison
  infix ==? (other numOption<T>) bool is numOption.this >>? fun(v T) => other >>? fun(w T) => v == w
  infix !=? (other numOption<T>) bool is numOption.this >>? fun(v T) => other >>? fun(w T) => v != w
  infix <?  (other numOption<T>) bool is numOption.this >>? fun(v T) => other >>? fun(w T) => v <  w
  infix <=? (other numOption<T>) bool is numOption.this >>? fun(v T) => other >>? fun(w T) => v <= w
  infix >?  (other numOption<T>) bool is numOption.this >>? fun(v T) => other >>? fun(w T) => v >  w
  infix >=? (other numOption<T>) bool is numOption.this >>? fun(v T) => other >>? fun(w T) => v >= w

  isZero => sign ==? 0

  sign numOption<i32> is
    numOption.this ? v T => v.sign
                   | nil => nil

  abs numOption<T> is
    numOption.this >>= v -> if v.sign >= 0 v else -?v

  redef asString string is
    numOption.this ? v T => v.asString
                   | nil => "--no value--"


# numOption with 1 argument provides an short-hand to wrap a value into a
# numOption
#
# Using this enables to write
#
#   o := numOption x
#
# insted of
#
#   o numOption<TypeOfX> := x
#
numOption<T> (o numOption<T>) => o