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).type) :
  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 type, 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 >>= v -> +v
  prefix -? numOption T is numOption.this >>= v -> -?v

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

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

  # comparison
  infix ==? (other numOption T) bool is numOption.this >>? v -> other >>? w -> v == w
  infix !=? (other numOption T) bool is numOption.this >>? v -> other >>? w -> v != w
  infix <?  (other numOption T) bool is numOption.this >>? v -> other >>? w -> v <  w
  infix <=? (other numOption T) bool is numOption.this >>? v -> other >>? w -> v <= w
  infix >?  (other numOption T) bool is numOption.this >>? v -> other >>? w -> v >  w
  infix >=? (other numOption T) bool is numOption.this >>? v -> other >>? w -> 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 (numeric T).type, o numOption T) => o


# type related to numOption declaring features not requiring an instance of numOption
#
numOptions(T (numeric T).type) : monads T (numOption T) is


  # return function
  #
  return (a T) => numOption a