handles.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 handles
#
# Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------
# handles provide a means to create handles that refer to update-able
# cells.
#
# handles is a state monad. It provides features to create several
# handles that refer to modifiable value and features to 'get', 'put' or
# 'update' this value.
#
# an example of using handles is shown below, handle (singular) is an
# alias to initialize a new handle with the given initial value. handle0 T
# is the type that allows passing around handles.
#
# ex_handles is
# hdl := handle 42
#
# say hdl.get
#
# x(h handle0 i32) unit =>
# b := hdl.put 17
# say b
# say hdl.get
#
# x hdl
#
# say hdl.get
#
# the example also shows the difference between handles and the mutate effect:
# while both provide a way to store and update a mutable value, a handle can be
# passed around between features. meanwhile, mutables are not a type that can be
# given to other features, only values can. handles essentially provide an
# abstraction of pointers, implemented natively in Fuzion.
#
private:public handles(
T, X type,
# the inner value of this monad
public v X,
# array containing values stored for the handles
#
# NYI: As soon as one-way monads are enforced, this array can be implemented
# using marray, reducing the overhead of an update from O(count) to O(1)!
#
private ar array T,
# action to be taken: plain monad, install or replace?
redef r effect_mode.val
) : oneway_monad X (handles T X) r
is
# number of handles created
private count => ar.length
# create a new instance with one additional handle
#
# the new handle can be accessed by 'result.last'
#
public new (
# initial value refered to by the new handle
w T
) handles T X
post
result.has_last
=>
na := array T count+1 (i -> if (i < count) ar[i] else w)
handles T X v na mode
# has one element been created using 'new'?
#
public has_last => count > 0
# return the last handle that was created by 'new'
#
public last
pre
has_last
=>
handle0 T count-1
# a one-way feature to create a new handle and update the monad
# in the current environment
#
/* env */
public create (
# initial value refered to by the new handle
w T
)
=>
(new w).last
# get the value refered to by a given handle
#
public get (
# a handle created by 'new'
h handle0 T
)
=>
ar[h.x]
# create a new instance with new value refered to by a given handle
#
public put (
# a handle created by 'new'
h handle0 T,
# the new value to be stored with 'h'
w T)
=>
handles T X v (ar.put h.x w) mode
# create a new instance with the value refered to by a given handle read and
# updated.
#
public update (
# a handle created by 'new'
h handle0 T,
# function calculcating the new value from the old value
f T->T
)
=>
update0 h.x f
# create a new instance with the value refered to by a given handle read and
# updated.
#
private update0 (
# a handle created by 'new'
x i32,
# function calculcating the new value from the old value
f T->T
)
=>
handles T X v (ar.put x (f ar[x])) mode
public infix >>= (f X -> handles T X) => bind X f
public bind(B type, f X -> handles T B) handles T B =>
handles T B (f v).v ar effect_mode.plain
public return( B type, w B) => handles T B w ar effect_mode.plain
# short-hand for creating and installing an empty set of handles of given type.
#
public handles(T type, rr ()->unit) =>
handles T unit unit (array T 0 x->do) (effect_mode.inst rr)
unit
# short-hand for creating an empty set of handles of given type.
#
public handles_(T type) => handles T unit unit (array T 0 x->do) effect_mode.plain
# short-hand for accessing handles monad for given type in current environment
#
public handles(T type) =>
(handles_type T).install_default
(handles T unit).env
# type of the reference to the cell that holds a value of type T which can be updated
# using the handles interface
#
private:public handle0(
T type,
# the index in 'handles.ar'
private x i32
)
is
# set value stored in this handle to new_x
#
public put(new_x T) is
_ := update old_x->new_x
# update value stored in this handle using f.
#
public update(f T->T) =>
(handles T).update0 x f
get
# get value stored in this handle
#
public get =>
(handles T).ar[x]
# unit type containing features related to handles but nor requiring an instance
#
handles_type(T type) is
# install default instance of handles
#
install_default unit =>
handles T unit unit (array T 0 x->do) effect_mode.default
unit
# initializes a new handle with the given initial value
#
# this uses the handles instance from the current environment
#
public handle(T type, v T) => (handles T).create v
last changed: 2024-03-07