7.1: adda/vmem'mgt/intro:
. in our virtual memory stack system
we are replacing each of the stack's
subprogram activation records (act'rec's)
with a pointer to a resizable object
(ie, it points to an expandable array in the heap );
thus, the stack [8.29:
-- if we didn't have a stackless architecture -- ]
becomes an array of pairs:
( return address
, pointer to act'rec
) . if our allotted ram is getting full,
we can file the obj's attached to earlier parts of the stack
or even file earlier segments of a very long stack .
Showing posts with label 1st-class functions. Show all posts
Showing posts with label 1st-class functions. Show all posts
2012-08-29
2012-08-26
obj' messaging to clarify what's functional
7.28: adda/function/
oop's obj' messaging as a syntax for inout params:
[8.8: 8.16: intro:
. the usual way to manage objects is to
define their interface with a datatype declaration;
eg, t.type: ( ... ) -- that interface can include
both subprograms ( f( x.t ) )
and obj'messages ( x'f ).
. up to now, that interface declaration
was the only place where we could
define obj'messages;
whereas, subprogram could be defined anywhere:
. there are various declare blocks
( package, record, subprogram, etc).
that can instantiate objects of type t;
eg, (.int: ... )
-- that's a block that returns an integer;
and, anywhere an object can be declared,
we can also declare subprograms that are
local to the current declare block .]
declare blocks can declare obj'messaging:
. obj'messaging can be seen as
a special style of parameter,
where f(inout x) is instead written as ( x`f ).
. in the context of a type declaration,
( x`f ) is declared simply as ( `f );
because, x is assumed to be
any of the datatype's instantiations;
so, we know what x's type is,
but in a subprogram's declaration of ( x`f )
x's type would not be known;
so, the sub's declaration
would look like this: ( (x.type)`f );
and, a generalization of this would be
(x.type1, y.type2, etc)`f
which is useful for making it obvious that
x,y,etc are all inout parameters;
then we can reserve the syntax ( f(x) )
for functional uses of x,
ie, where ( f ) is not modifying x
nor modifying anything x can access;
ie, if you want to pass a pointer, p,
for the purposes of modifying p's target,
then the needed syntax is p`f, not f(p).
oop's obj' messaging as a syntax for inout params:
[8.8: 8.16: intro:
. the usual way to manage objects is to
define their interface with a datatype declaration;
eg, t.type: ( ... ) -- that interface can include
both subprograms ( f( x.t ) )
and obj'messages ( x'f ).
. up to now, that interface declaration
was the only place where we could
define obj'messages;
whereas, subprogram could be defined anywhere:
. there are various declare blocks
( package, record, subprogram, etc).
that can instantiate objects of type t;
eg, (.int: ... )
-- that's a block that returns an integer;
and, anywhere an object can be declared,
we can also declare subprograms that are
local to the current declare block .]
declare blocks can declare obj'messaging:
. obj'messaging can be seen as
a special style of parameter,
where f(inout x) is instead written as ( x`f ).
. in the context of a type declaration,
( x`f ) is declared simply as ( `f );
because, x is assumed to be
any of the datatype's instantiations;
so, we know what x's type is,
but in a subprogram's declaration of ( x`f )
x's type would not be known;
so, the sub's declaration
would look like this: ( (x.type)`f );
and, a generalization of this would be
(x.type1, y.type2, etc)`f
which is useful for making it obvious that
x,y,etc are all inout parameters;
then we can reserve the syntax ( f(x) )
for functional uses of x,
ie, where ( f ) is not modifying x
nor modifying anything x can access;
ie, if you want to pass a pointer, p,
for the purposes of modifying p's target,
then the needed syntax is p`f, not f(p).
Labels:
1st-class functions,
adda,
functional,
oop,
sandbox,
security
2012-08-01
Python's generators and coroutines
2.16: adda/cstr/1st-class functions/
generators and coroutines:
. a generator in python
is a function identified by it's body:
it's calling yield instead of return .
. the easier way to view this
in a typed lang, like adda,
is to set the return type as a stream ?
. streams are conceptually like files
so they should work like files;
eg, to restart sequence do an
f.open(name of generator instead of file) .
. streams are like sequences, in that
seek(n) can be done by restarting the generator
and asking for an nth item .
. the coroutine in python is like a generator;
but instead of streaming output,
it has a streaming input:
f`open mycoroutine(init);
f`put (some data to send to it) .
. it could do put's to output, and get's to input;
being both a generator and a coroutine .
generators and coroutines:
. a generator in python
is a function identified by it's body:
it's calling yield instead of return .
. the easier way to view this
in a typed lang, like adda,
is to set the return type as a stream ?
. streams are conceptually like files
so they should work like files;
eg, to restart sequence do an
f.open(name of generator instead of file) .
. streams are like sequences, in that
seek(n) can be done by restarting the generator
and asking for an nth item .
. the coroutine in python is like a generator;
but instead of streaming output,
it has a streaming input:
f`open mycoroutine(init);
f`put (some data to send to it) .
. it could do put's to output, and get's to input;
being both a generator and a coroutine .
2012-04-30
pre- and post-conditions
4.18: adda/cstr/function/pre- and post-conditions:
. we need a syntax that extends a function's type expression
to include the function's pre- and post-conditions
which are predicates that reduce the function's space
by testing both the input and output for certain conditions .
. math syntax sometimes uses the (|) operator for such work .
. perhaps the new syntax for a function type literal could be:
(x.t).t | (pre-condition; post-condition) .
. we need a syntax that extends a function's type expression
to include the function's pre- and post-conditions
which are predicates that reduce the function's space
by testing both the input and output for certain conditions .
. math syntax sometimes uses the (|) operator for such work .
. perhaps the new syntax for a function type literal could be:
(x.t).t | (pre-condition; post-condition) .
Labels:
1st-class functions,
adda,
cstr
2012-02-29
adda's equivalent to Python decorators
2.26: adda/functions/Python decorators:
. a note of mine that was wondering how to
impl' AOP (aspect oriented prog'ing)
[@] 11.9.16: mis.adds/aop (aspect oriented prog'ing)
had me responding now that
a first-class lisp system would make it easy to
add AOP later .
. the topic of higher-order function
(the class of functions that
input and output other functions)
reminded me that python does decorators;
the syntax is:
@fun1 @fun2 ... def funx(): body .
. an adda-style syntax for that would be:
funx().proc: fun1 fun2 body .
. a note of mine that was wondering how to
impl' AOP (aspect oriented prog'ing)
[@] 11.9.16: mis.adds/aop (aspect oriented prog'ing)
had me responding now that
a first-class lisp system would make it easy to
add AOP later .
. the topic of higher-order function
(the class of functions that
input and output other functions)
reminded me that python does decorators;
the syntax is:
@fun1 @fun2 ... def funx(): body .
. an adda-style syntax for that would be:
funx().proc: fun1 fun2 body .
2012-01-31
inout-mode parameters
1.4: adda/syntax/{inout, out}-mode parameters:
. {inout, out}-mode parameters are special because
they create sideaffects .
[1.6:
. anyone coming from any other language
will be assuming that if you pass a pointer
then it means you get to modify
anything accessable by that pointer;
-- that is the whole point of pointers,
unless their targets are typed as being read-only mode;
however,
other languages have created a lot of bugs too,
so we really should carefully reconsider
designing our functions to be functional by default .
1.7:
. the usual understanding of aParam typed as
pointer to int is read-only pointer to inout int;
whereas, what we are assuming here is
read-only pointer to read-only int .
. the usual understanding of an
inout param typed as pointer to int is
inout pointer to inout int;
whereas, what we are assuming here is
inout pointer to read-only int .]
. the Ada goto label was chosen as notation that alarms,
and that's why I had chosen it for out-moding params;
the param x, a pointer to int,
out-moding on both the pointer and the int; [1.6:
however, something similar and easier to read is (^);
will it be confused with the power operator?
if it's placed at the back of the typemark,
then it clearly gives a context to reader and parser .]
. the most elegant way to define inout mode
is to unify it with its implied activity: inititialization .
. param's can specify default init values,
and if that init is the param' being defined,
that would imply inout mode
while doing something else essential . [1.6:
. however,
it seems counter to the intended model,
because defaults are supposed to tell you
what happens when you fail to supply the actual param,
implying that it's optional,
by contrast, what we're trying to say is:
not only is the param' instantiation not optional,
but the actual param's initial value is not optional either;
so, another idea is to precede the (out)-symbol
with an (in)-symbol such as (&);
since the default is in-mode,
and t^ means t is out-mode,
so t&^ would say t is in-mode & out-mode .
. if that seems like a stretch, then how about t'^ ?
the apostrophe seems like an arrow pointing down,
while the caret is arrow pointing up,
hence an iconic representation of inout;
and being on the back side of types,
it would fit in with the proposed typemark for
rom (read-only mem): t! .]-1.6
. when types contain types,
as in /.int (the type"pointer to int)
we need a notation to specify
which of those types can be modified;
therefore we can not
simply apply the notation to the parameter name,
as is done in other languages .
[1.7:
. we can provide that as an option though;
eg # inout aParam/.int!
--. this provides read-write access to
a pointer to a read-only int
(same as our aParam/'^.int);
eg # inout aParam/!.int
-- read-only access to a pointer to a read&writable int
(same as aParam/.int'^).]
[1.6:
. notice that, among container types such as
/.int (a pointer.type containing the int.type)
if you don't need the value of a param
(and are thus giving it the attribute out-mode),
you certainly don't need the values of any type within;
eg, /^.int'^ wouldn't make sense because
how can there be a value to get from the int
when there no value expected from
the pointer that is needed to access the int?
. if something like "(/^.int'^ )
could never make sense to some users anyway,
they should be allowed to use simple english too:
{out, inout } -- copy is the default .
. inout-mode could be understood to be
a property possessed by a type,
hence the use of the possessive operator:
/'^.int^ becomes /`inout.int`out (read:
pointer's inout to int's out ).
. another idea is that
{out, inout} would be functions over types,
so instead of needing a possessive operator,
you could simply use a space:
x/'^.int^ becomes x.inout /.out int .
. in this case, {inout, out} need to be reserved words?
we could allow renaming them,
eg, {o, io} or {wo, rw} might be popular .]-1.6
[1.6:
. by letting {out, inout} be a function,
it would also make sense to do it Ada's way:
letting the inout apply to the param itself,
instead of applying to each of the param's nested types;
eg,
inout x/.int -- just give me inout everything!
. why do you suppose Ada doesn't facilitate
applying {inout, out} to each of the param's
nested types?
[1.7: besides the fact that it's param's can
only trivially be container types
(you need to use a single type name
or a pointer to typename)]
. perhaps they are mostly concerned with
a transaction model:
this is where the implementation of out-mode
has the option of either using a reference,
or else doing a copy-in then copy-out .
. doing it my way could save much copying,
because suppose you have a pointer to a huge tree;
if all you want to do is modify the pointer,
then the copy-in©-out system
doesn't have to copy that huge tree for you! ]-1.6
1.7: web: ada parameters:
. Ada's rationale for not supporting pass-by-reference:
{. parameter passing by reference for access types
is not expected by most algorithms and will result in
those algorithms being incorrect .}
. access types are already unique in that the programmer is
permitted explicitly to manipulate references and construct aliases:
This is the purpose of access types,
and programmers using such types are asserting that
they wish to take control of all references and aliases.
Accordingly, the parameter passing should not generate
extra references and aliases of which the programmer is unaware;
therefore, all parameter passing for access types
should be by copy.
A final problem with parameter passing by reference
is that this mechanism will be almost impossible to achieve
(or at least, very costly) on distributed systems
and when dealing with systems having multiple address spaces.
--
. but the 2012 version does support them .
ada parameters/syntax:
2005 parameter_specification ::=
defining_identifier_list : mode [null_exclusion]
subtype_mark [:= default_expression]
| defining_identifier_list : access_definition
[:= default_expression]
2012 parameter_specification ::=
defining_identifier_list : [aliased] mode [null_exclusion]
subtype_mark [:= default_expression]
| defining_identifier_list : access_definition
[:= default_expression]
access_definition ::=
[null_exclusion] access [constant] subtype_mark
| [null_exclusion] access [protected]
procedure parameter_profile
| [null_exclusion] access [protected]
function parameter_and_result_profile access subtype_mark
. {inout, out}-mode parameters are special because
they create sideaffects .
[1.6:
. anyone coming from any other language
will be assuming that if you pass a pointer
then it means you get to modify
anything accessable by that pointer;
-- that is the whole point of pointers,
unless their targets are typed as being read-only mode;
however,
other languages have created a lot of bugs too,
so we really should carefully reconsider
designing our functions to be functional by default .
1.7:
. the usual understanding of aParam typed as
pointer to int is read-only pointer to inout int;
whereas, what we are assuming here is
read-only pointer to read-only int .
. the usual understanding of an
inout param typed as pointer to int is
inout pointer to inout int;
whereas, what we are assuming here is
inout pointer to read-only int .]
. the Ada goto label was chosen as notation that alarms,
and that's why I had chosen it for out-moding params;
eg, x<</.int>>
would be used for havingthe param x, a pointer to int,
out-moding on both the pointer and the int; [1.6:
however, something similar and easier to read is (^);
will it be confused with the power operator?
if it's placed at the back of the typemark,
then it clearly gives a context to reader and parser .]
. the most elegant way to define inout mode
is to unify it with its implied activity: inititialization .
. param's can specify default init values,
and if that init is the param' being defined,
that would imply inout mode
while doing something else essential . [1.6:
. however,
it seems counter to the intended model,
because defaults are supposed to tell you
what happens when you fail to supply the actual param,
implying that it's optional,
by contrast, what we're trying to say is:
not only is the param' instantiation not optional,
but the actual param's initial value is not optional either;
so, another idea is to precede the (out)-symbol
with an (in)-symbol such as (&);
since the default is in-mode,
and t^ means t is out-mode,
so t&^ would say t is in-mode & out-mode .
. if that seems like a stretch, then how about t'^ ?
the apostrophe seems like an arrow pointing down,
while the caret is arrow pointing up,
hence an iconic representation of inout;
and being on the back side of types,
it would fit in with the proposed typemark for
rom (read-only mem): t! .]-1.6
. when types contain types,
as in /.int (the type"pointer to int)
we need a notation to specify
which of those types can be modified;
therefore we can not
simply apply the notation to the parameter name,
as is done in other languages .
[1.7:
. we can provide that as an option though;
eg # inout aParam/.int!
--. this provides read-write access to
a pointer to a read-only int
(same as our aParam/'^.int);
eg # inout aParam/!.int
-- read-only access to a pointer to a read&writable int
(same as aParam/.int'^).]
[1.6:
. notice that, among container types such as
/.int (a pointer.type containing the int.type)
if you don't need the value of a param
(and are thus giving it the attribute out-mode),
you certainly don't need the values of any type within;
eg, /^.int'^ wouldn't make sense because
how can there be a value to get from the int
when there no value expected from
the pointer that is needed to access the int?
. if something like "(/^.int'^ )
could never make sense to some users anyway,
they should be allowed to use simple english too:
{out, inout } -- copy is the default .
. inout-mode could be understood to be
a property possessed by a type,
hence the use of the possessive operator:
/'^.int^ becomes /`inout.int`out (read:
pointer's inout to int's out ).
. another idea is that
{out, inout} would be functions over types,
so instead of needing a possessive operator,
you could simply use a space:
x/'^.int^ becomes x.inout /.out int .
. in this case, {inout, out} need to be reserved words?
we could allow renaming them,
eg, {o, io} or {wo, rw} might be popular .]-1.6
[1.6:
. by letting {out, inout} be a function,
it would also make sense to do it Ada's way:
letting the inout apply to the param itself,
instead of applying to each of the param's nested types;
eg,
inout x/.int -- just give me inout everything!
. why do you suppose Ada doesn't facilitate
applying {inout, out} to each of the param's
nested types?
[1.7: besides the fact that it's param's can
only trivially be container types
(you need to use a single type name
or a pointer to typename)]
. perhaps they are mostly concerned with
a transaction model:
this is where the implementation of out-mode
has the option of either using a reference,
or else doing a copy-in then copy-out .
. doing it my way could save much copying,
because suppose you have a pointer to a huge tree;
if all you want to do is modify the pointer,
then the copy-in©-out system
doesn't have to copy that huge tree for you! ]-1.6
1.7: web: ada parameters:
. Ada's rationale for not supporting pass-by-reference:
{. parameter passing by reference for access types
is not expected by most algorithms and will result in
those algorithms being incorrect .}
. access types are already unique in that the programmer is
permitted explicitly to manipulate references and construct aliases:
This is the purpose of access types,
and programmers using such types are asserting that
they wish to take control of all references and aliases.
Accordingly, the parameter passing should not generate
extra references and aliases of which the programmer is unaware;
therefore, all parameter passing for access types
should be by copy.
A final problem with parameter passing by reference
is that this mechanism will be almost impossible to achieve
(or at least, very costly) on distributed systems
and when dealing with systems having multiple address spaces.
--
. but the 2012 version does support them .
ada parameters/syntax:
2005 parameter_specification ::=
defining_identifier_list : mode [null_exclusion]
subtype_mark [:= default_expression]
| defining_identifier_list : access_definition
[:= default_expression]
2012 parameter_specification ::=
defining_identifier_list : [aliased] mode [null_exclusion]
subtype_mark [:= default_expression]
| defining_identifier_list : access_definition
[:= default_expression]
access_definition ::=
[null_exclusion] access [constant] subtype_mark
| [null_exclusion] access [protected]
procedure parameter_profile
| [null_exclusion] access [protected]
function parameter_and_result_profile access subtype_mark
Labels:
1st-class functions,
adda,
syntax,
type
generic type vs container type
1.4: adda/type/{generic, container}-type def's:
. there is a syntax for parametric types generally,
with multiple params that include
both types and non-types ? yes:
[1.6:
. the parameterized type is a sort of generic;
so, there are 2 points at which it is instantiated:
once to define the concrete type,
and then again for each use of that concrete type
in defining an obj' instance .
. to distinguish these,
use the terms {generic, container}-type .
. the {array, pointer} are really containers;
on the way to defining more container types,
you can use a generic type
which then must be instantiated
before use by container obj's .
. a container type could accept a record type as its leaf;
then each of those record fields
could be instantiations of a generic-type
that could return a container-type .
. the generic-types should not need
separate instantiation:
[1.7: eg,
( myLeafType.type: gentype(init)
; x.myLeafType; )
can also be done as x.gentype(init) .]
. here's a combination of generic and container instantiations
in one term:
pointertype(inits for variant selection).myLeafType .
. arrays, pointers, and functions are container types;
how are new container types defined ?
. recall that pointers and arrays are
types of functions [expressing container types]
but, can new [container] types be
defined like functions without confusion ?
yes:
. a function where the arg is of type .type;
eg, pointer.type is defined as:
/(type).type;
this works with these rules:
(1) function args are not required to be paren'd,
(2) types are preceded by a dot:
/.txt = /(.txt).
. there is a syntax for parametric types generally,
with multiple params that include
both types and non-types ? yes:
[1.6:
. the parameterized type is a sort of generic;
so, there are 2 points at which it is instantiated:
once to define the concrete type,
and then again for each use of that concrete type
in defining an obj' instance .
. to distinguish these,
use the terms {generic, container}-type .
. the {array, pointer} are really containers;
on the way to defining more container types,
you can use a generic type
which then must be instantiated
before use by container obj's .
. a container type could accept a record type as its leaf;
then each of those record fields
could be instantiations of a generic-type
that could return a container-type .
. the generic-types should not need
separate instantiation:
[1.7: eg,
( myLeafType.type: gentype(init)
; x.myLeafType; )
can also be done as x.gentype(init) .]
. here's a combination of generic and container instantiations
in one term:
pointertype(inits for variant selection).myLeafType .
. arrays, pointers, and functions are container types;
how are new container types defined ?
. recall that pointers and arrays are
types of functions [expressing container types]
but, can new [container] types be
defined like functions without confusion ?
yes:
. a function where the arg is of type .type;
eg, pointer.type is defined as:
/(type).type;
this works with these rules:
(1) function args are not required to be paren'd,
(2) types are preceded by a dot:
/.txt = /(.txt).
Labels:
1st-class functions,
adda,
generics,
type
adda minimizes paretheses
1.3: adda/syntax/lists of algorithm literals:
. the comma-semicolon syntax for lists
( ,,, ; ,,,,, ; ,,, ) would be confused with
those of an algorithm literal,
( ,,,: ; ;;; ,,,:; ;;; )
unless the algorithm literal is parenthesized;
( ,,, ; ,,( ,,,: ; ;;; ,,,:; ;;; ), ; ,,, )
that should be a general requirement
with the exception that
a file already constitutes a parenthesis .
[1.6: (interactive mode is a type of streamed file;
and adding the paren's would supress execution
until the closing paren' was added) .]
. with that requirement in place,
I can feel more confident designing
subprogram calls without paren's
[@] adda/syntax/subprogram calls without paren's
adda/syntax/
subprogram calls without paren's
. one thing I was taught by lisp counter/zealotry
is that if a language is to have
any chance of being popular
it should go out of its way to
avoid excessive parentheses!
. any symbol that is declared as a function
and is found in a sequence of statements,
can use the form: f x,y,z;
instead of f(x,y,z) .
. if you have: f g x,y;
that should be parsed as f(g(x,y)) ?
at least according to the
nested-if rule:
(if * then if * then * else *)
-- that would be parsed
like so:
if * then (if * then * else *)
rather than:
if * then (if * then * ) else * .
. but what does that do for the rule about
lists requiring paren's when nested in lists?
[@] adda/syntax/lists of algorithm literals
. moot: a unary arg is not a list .
. the comma-semicolon syntax for lists
( ,,, ; ,,,,, ; ,,, ) would be confused with
those of an algorithm literal,
( ,,,: ; ;;; ,,,:; ;;; )
unless the algorithm literal is parenthesized;
( ,,, ; ,,( ,,,: ; ;;; ,,,:; ;;; ), ; ,,, )
that should be a general requirement
with the exception that
a file already constitutes a parenthesis .
[1.6: (interactive mode is a type of streamed file;
and adding the paren's would supress execution
until the closing paren' was added) .]
. with that requirement in place,
I can feel more confident designing
subprogram calls without paren's
[@] adda/syntax/subprogram calls without paren's
adda/syntax/
subprogram calls without paren's
. one thing I was taught by lisp counter/zealotry
is that if a language is to have
any chance of being popular
it should go out of its way to
avoid excessive parentheses!
. any symbol that is declared as a function
and is found in a sequence of statements,
can use the form: f x,y,z;
instead of f(x,y,z) .
. if you have: f g x,y;
that should be parsed as f(g(x,y)) ?
at least according to the
nested-if rule:
(if * then if * then * else *)
-- that would be parsed
like so:
if * then (if * then * else *)
rather than:
if * then (if * then * ) else * .
. but what does that do for the rule about
lists requiring paren's when nested in lists?
[@] adda/syntax/lists of algorithm literals
. moot: a unary arg is not a list .
Labels:
1st-class functions,
adda,
cstr,
syntax
2011-06-28
1st-class functions and various environs
adda/oop/1st-class functions:
5.16:
. a function's owner is the environs in which
the function's body is defined; [6.1:
a top-level subprogram is owned by the library,
and thereby has access to the standard lib' .]
. most functions are owned by types:
the type's body provides the environs;
but 1st-class function support means that
an aggregate's components may be a function,
in which case, the agg is the owner,
so the agg's body and its other components
become the function's environs .
[5.18: clarification:
. agg's can have bodies like Ada packages;
and if the agg' body contains the function body
only then does the agg' own the function .
5.31: 6.28:
. the agg'component can also be
a pointer to an external function;
such a function then has no way to reach
agg' components;
conversely, Ada's stub declaration allows for
an agg'owned function to be defined externally;
it's still declared locally if not defined so,
and declaration is what gives it local access,
and a locality to call its own .]
[5.17:
. an agg's components can be addressed in 2 ways:
# directly:
. a function it owns knows what's available
and reaches an external x with (../x) .
# a filesystem approach:
. the function can get a list of
the names of surrounding components,
just as a human asks a filesystem
for a directory listing .
--
. a function's use of (self`name) could return
the name of the component it's been assigned to ... 6.1:
. it could be assigned to more than
one component of its owner;
so, that would have to be a list .]
5.31: deleting self:
. can a function delete itself from a agg'?
it can reach and modify other components
from within the agg' it's a component of;
so why not be able to delete itself?
it could still run after such a deletion
because it's an active process
and each act'rec on the stack display
is paired with a pointer to the associated code . [6.1:
. one reason for deleting self could be
a varying method pattern:
it calls multiple agg'components,
some of which may be self,
and changes methods to meet new conditions .]
5.17: all accesses must be cap'based:
[5.16:
. how would an external function
ask for access to the class var's?
. it can't use ../ because it's
local to an instance, whereas
class var's are local to the type's body .
. it could work like a filesystem,
where functions can request a list
of their owner's class var's .
. the type's body allows access by
populating the class's locals list
with the addresses it wishes to share
rather than leaving the list null ...]
...
. the idea of assignable functions
having access to class var's
must be integrated with a security model
that considers who's asking for the access
and who's affected by it .
. it's not just a matter of selecting
which locals are visible,
but also deciding which functions
can have that access:
the filtering might be by function-type,
function-authors, or function-libraries .
5.18: dimensions of environs:
. a function.ptr assigned to an agg' component
is just like when passed to a subprogram param;
in either of these cases,
a function body's own environ
is not the same as caller's body .
. there can also be structural environs
(what agg'path was used for accessing
a copy of the function's address).
. when a call is made, the function gets a
return address that is a shortcut to
this scope path:
main/sub/nth step/m-th step of sub.body(eg, a loop) .
. that leads to the call's location
which includes the data path needed to
access the function: [6.28: ...
by looking on the stack's return address,
and then looking at the code
that launched that function call,
we are finding the structural environs .]
. some variants of lisp
feature dynamic scope
in which a called function can expect access to
the caller's environ's .
. is there any language that provides
access to the structural environs?
. lisp functions can also know
who their caller is,
and what their caller's code is .
. it seems like the
full generalization of that would be
pointers to all related structures:
the owner, the caller,
the call or return point,
and the path of caller's access to function .
. practically though,
the simple and safe way is
accessing only what's available at compile time .
. if the function wants to share the caller's locals,
it can declare an inout param
that callers need to fill;
if the caller wants a function to share,
it can take ownership of the function .
5.16:
. a function's owner is the environs in which
the function's body is defined; [6.1:
a top-level subprogram is owned by the library,
and thereby has access to the standard lib' .]
. most functions are owned by types:
the type's body provides the environs;
but 1st-class function support means that
an aggregate's components may be a function,
in which case, the agg is the owner,
so the agg's body and its other components
become the function's environs .
[5.18: clarification:
. agg's can have bodies like Ada packages;
and if the agg' body contains the function body
only then does the agg' own the function .
5.31: 6.28:
. the agg'component can also be
a pointer to an external function;
such a function then has no way to reach
agg' components;
conversely, Ada's stub declaration allows for
an agg'owned function to be defined externally;
it's still declared locally if not defined so,
and declaration is what gives it local access,
and a locality to call its own .]
[5.17:
. an agg's components can be addressed in 2 ways:
# directly:
. a function it owns knows what's available
and reaches an external x with (../x) .
# a filesystem approach:
. the function can get a list of
the names of surrounding components,
just as a human asks a filesystem
for a directory listing .
--
. a function's use of (self`name) could return
the name of the component it's been assigned to ... 6.1:
. it could be assigned to more than
one component of its owner;
so, that would have to be a list .]
5.31: deleting self:
. can a function delete itself from a agg'?
it can reach and modify other components
from within the agg' it's a component of;
so why not be able to delete itself?
it could still run after such a deletion
because it's an active process
and each act'rec on the stack display
is paired with a pointer to the associated code . [6.1:
. one reason for deleting self could be
a varying method pattern:
it calls multiple agg'components,
some of which may be self,
and changes methods to meet new conditions .]
5.17: all accesses must be cap'based:
[5.16:
. how would an external function
ask for access to the class var's?
. it can't use ../ because it's
local to an instance, whereas
class var's are local to the type's body .
. it could work like a filesystem,
where functions can request a list
of their owner's class var's .
. the type's body allows access by
populating the class's locals list
with the addresses it wishes to share
rather than leaving the list null ...]
...
. the idea of assignable functions
having access to class var's
must be integrated with a security model
that considers who's asking for the access
and who's affected by it .
. it's not just a matter of selecting
which locals are visible,
but also deciding which functions
can have that access:
the filtering might be by function-type,
function-authors, or function-libraries .
5.18: dimensions of environs:
. a function.ptr assigned to an agg' component
is just like when passed to a subprogram param;
in either of these cases,
a function body's own environ
is not the same as caller's body .
. there can also be structural environs
(what agg'path was used for accessing
a copy of the function's address).
. when a call is made, the function gets a
return address that is a shortcut to
this scope path:
main/sub/nth step/m-th step of sub.body(eg, a loop) .
. that leads to the call's location
which includes the data path needed to
access the function: [6.28: ...
by looking on the stack's return address,
and then looking at the code
that launched that function call,
we are finding the structural environs .]
. some variants of lisp
feature dynamic scope
in which a called function can expect access to
the caller's environ's .
. is there any language that provides
access to the structural environs?
. lisp functions can also know
who their caller is,
and what their caller's code is .
. it seems like the
full generalization of that would be
pointers to all related structures:
the owner, the caller,
the call or return point,
and the path of caller's access to function .
. practically though,
the simple and safe way is
accessing only what's available at compile time .
. if the function wants to share the caller's locals,
it can declare an inout param
that callers need to fill;
if the caller wants a function to share,
it can take ownership of the function .
Labels:
1st-class functions,
adda,
oop
2011-05-02
function notation classes
4.12: adda/cstr/function notation classes:
. how does the type mgt express
parsing particulars?
eg, some infixes can be combined:
a*b*c = *(a,b,c),
whereas, a /b /c = *(a, /b, /c) .
so then (/) is not listable ...
types of declarations:
# unary:
eg, sin(a);
# infix listable:
*(a, ...) -- = a * b * c * ....
--. implies associativity;
ie, (a*b)*c = a*(b*c) = *(a,b,c).
# infix binary:
^(a,b) -- a^b^c = a^(b^c)
-- implies non-associativity;
ie, (a^b)^c =/= a^(b^c);
and, the given rule specifies which way to parse .
--. precedence is indicated by
the order in which operators are declared .
. can also be a prefix .
-- undeclared are assumed to be 2 args of the same type
(ie, the same supertype).
# infix or unary:
/(a=1,b) -- = 1 * /b;
-(a=0,b) -- = 0 + -b
-- /a = 1/a;
# nofix: no arg expected;
eg, pi, e, dimensions,
marks an EOterm
(is also trivially a prefix)
-- declared as having no args: x.t .
# postfix:
(x)!, -- factorial's declaration,
(having multiple parameters but of various types
counts as 1 arg of type record ):
(x.t, x.u)!.v .
[4.30: {postfix, prefix} are treated as separate functions,
like so:
()!, -- postfix
!, !() -- prefix .]
. each type class can overload an operator
as either {unary#prefix, unary#post}
or -- as in the case of Number.type --
{ infix (2 args)
, prefix (other numbers of args)
} . a symbol can be designated as
both pre- and post-fix
but cannot be both post- and in-fix .
. the one place math has a postfix is (x!).
in that case,
it's at the end of a term just like an infix
so the only way to be certain that a postfix
is not the infix found between terms
is by disallowing operators from being
both infix's and postfix's .
. postfix's can, however,
double as prefix's,
as can the infix's;
so, expecting a term and finding (!)
means the (!) is a prefix to that term;
whereas, expecting an infix or EOse
(end of subexpression) and finding (!)
means the (!) is a postfix .
. a subexpression can have multiple terms
separated by infix's;
terms are defined as being either:
nofix's: symbols accepting no args;
or a prefix followed by an arg .
. a subexpression is anything terminated by
an enclosure`end:
ie,
, . ; ) } .> end-of-file ] .
. how does the type mgt express
parsing particulars?
eg, some infixes can be combined:
a*b*c = *(a,b,c),
whereas, a /b /c = *(a, /b, /c) .
so then (/) is not listable ...
types of declarations:
# unary:
eg, sin(a);
# infix listable:
*(a, ...) -- = a * b * c * ....
--. implies associativity;
ie, (a*b)*c = a*(b*c) = *(a,b,c).
# infix binary:
^(a,b) -- a^b^c = a^(b^c)
-- implies non-associativity;
ie, (a^b)^c =/= a^(b^c);
and, the given rule specifies which way to parse .
--. precedence is indicated by
the order in which operators are declared .
. can also be a prefix .
-- undeclared are assumed to be 2 args of the same type
(ie, the same supertype).
# infix or unary:
/(a=1,b) -- = 1 * /b;
-(a=0,b) -- = 0 + -b
-- /a = 1/a;
# nofix: no arg expected;
eg, pi, e, dimensions,
marks an EOterm
(is also trivially a prefix)
-- declared as having no args: x.t .
# postfix:
(x)!, -- factorial's declaration,
(having multiple parameters but of various types
counts as 1 arg of type record ):
(x.t, x.u)!.v .
[4.30: {postfix, prefix} are treated as separate functions,
like so:
()!, -- postfix
!, !() -- prefix .]
. each type class can overload an operator
as either {unary#prefix, unary#post}
or -- as in the case of Number.type --
{ infix (2 args)
, prefix (other numbers of args)
} . a symbol can be designated as
both pre- and post-fix
but cannot be both post- and in-fix .
. the one place math has a postfix is (x!).
in that case,
it's at the end of a term just like an infix
so the only way to be certain that a postfix
is not the infix found between terms
is by disallowing operators from being
both infix's and postfix's .
. postfix's can, however,
double as prefix's,
as can the infix's;
so, expecting a term and finding (!)
means the (!) is a prefix to that term;
whereas, expecting an infix or EOse
(end of subexpression) and finding (!)
means the (!) is a postfix .
. a subexpression can have multiple terms
separated by infix's;
terms are defined as being either:
nofix's: symbols accepting no args;
or a prefix followed by an arg .
. a subexpression is anything terminated by
an enclosure`end:
ie,
, . ; ) } .> end-of-file ] .
Labels:
1st-class functions,
adda,
cstr,
syntax
2011-02-28
self as used by interfaces and anonymous algorithms
2.28: adda/lexeme/self/for anon'algor's and interfaces:
. the word"self is useful in 2 contexts:
# anonymous algorithm:
it means the current algorithm,
# type`interface:
it means a current instance of that type;
eg, t.type: ( self!: defines a postix operator).
. if there is an algorithm in the header
(eg, to declare algorithms that won't change
for some reason...)
then the usual scope rules prevail .
. the word"self is useful in 2 contexts:
# anonymous algorithm:
it means the current algorithm,
# type`interface:
it means a current instance of that type;
eg, t.type: ( self!: defines a postix operator).
. if there is an algorithm in the header
(eg, to declare algorithms that won't change
for some reason...)
then the usual scope rules prevail .
Labels:
1st-class functions,
adda,
interface,
lexeme,
oop
2010-03-30
anonymous and literal adt's
3.19: adda/oop/anonymous types:
. abstract typing means a symbol's useage
is declared in terms of operations;
eg,
written with an anonymous type as:
a benefit is that a simpler syntax
with fewer exceptions;
the alternative is disallowing all type literals;
ie, having to name all types !
3.19: todo.adda/oop/abstract literals:
. adda still needs a way to express
literal abstract types symbolically
rather than as a list of operator literals .
... that gets back to question of
how to express a union of types:
ie, I'm not listing the available operations
I'm listing the names of types
that will list available operations .
3.21: adda/oop/abstract type literals:
. how is adda allowing new types in terms of old
without assuming the old and new are
assignment compatable ?
eg, does it impl' type color with number
yet still warn of type mismatch when
number is used as a color?
--. actually,
that wouldn't be a good example since
the system should support physics' way of
typing numeric obj's with dimensions;
ie, (x color) returns a color defined by
the numeric value of x .
. adda still needs a way to say
a type's interface is the same as a given type
but also say they are not compatable types;
eg,
my.type: another.type`face;
--. here,
a type's face returns an interface literal;
eg,
the literal face of numbers is
(face u face ...)
--. if a face is a set
are you calling the face literal a set notation ?
a set is any unordered list in which
duplicates can be tossed .
review of aggregate-type`literals:
record var with anonymous type: rec.(v.t, ..)
record type: (v.t, ...)
array var with anonymous type: array#(v.t, ..).t
array type: #(v.t, ...).t .
-- array type literals can also symbolic:
#enum-range-symbol.t,
or enum range literal:
#{e1, e2, ...}.t .
. notice functions are sets {,,,}
but arrays are structs (,,,)
according to the design of their literals;
there were 2 issues to juggle:
have all struct's literals indicate type uniquely,
but also keep things making sense without special rules .
. for types' literals
the combination of enclosure and content syntax
are what identify which type they are:
symbols are assumed to be any number of args
unless the arg is specified;
an operator listed without a parenthetical
means 1,2, or more args, with infix accepted .
. abs() means one or more args
but as prefix only, not infix .
. for functions with multiple param's
of various types: f(x.T1, y.T2, ...)
when an param's type is not given
that means its the same type as
the adt's name;
. if num.type has this function:
image().#.char
it means:
image(x.num).#.char .
. abstract typing means a symbol's useage
is declared in terms of operations;
eg,
( num.type: <+, -, /, *>;
, x.num .
)
. that example could instead bewritten with an anonymous type as:
x.<+, -, /, *>
. despite that being harder to read,a benefit is that a simpler syntax
with fewer exceptions;
the alternative is disallowing all type literals;
ie, having to name all types !
3.19: todo.adda/oop/abstract literals:
. adda still needs a way to express
literal abstract types symbolically
rather than as a list of operator literals .
... that gets back to question of
how to express a union of types:
ie, I'm not listing the available operations
I'm listing the names of types
that will list available operations .
3.21: adda/oop/abstract type literals:
. how is adda allowing new types in terms of old
without assuming the old and new are
assignment compatable ?
eg, does it impl' type color with number
yet still warn of type mismatch when
number is used as a color?
--. actually,
that wouldn't be a good example since
the system should support physics' way of
typing numeric obj's with dimensions;
ie, (x color) returns a color defined by
the numeric value of x .
. adda still needs a way to say
a type's interface is the same as a given type
but also say they are not compatable types;
eg,
my.type: another.type`face;
--. here,
a type's face returns an interface literal;
eg,
the literal face of numbers is
<+,-,/,*, abs(), sign(), ...> .
. to merge many faces, use union:(face u face ...)
--. if a face is a set
are you calling the face literal a set notation ?
a set is any unordered list in which
duplicates can be tossed .
review of aggregate-type`literals:
record var with anonymous type: rec.(v.t, ..)
record type: (v.t, ...)
array var with anonymous type: array#(v.t, ..).t
array type: #(v.t, ...).t .
-- array type literals can also symbolic:
#enum-range-symbol.t,
or enum range literal:
#{e1, e2, ...}.t .
. notice functions are sets {,,,}
but arrays are structs (,,,)
according to the design of their literals;
there were 2 issues to juggle:
have all struct's literals indicate type uniquely,
but also keep things making sense without special rules .
. for types' literals
the combination of enclosure and content syntax
are what identify which type they are:
enum: {symbol, ..}
record: (v.t, ...)
function: (x).t
adt: < symbol, ...>
. in the adt,symbols are assumed to be any number of args
unless the arg is specified;
an operator listed without a parenthetical
means 1,2, or more args, with infix accepted .
. abs() means one or more args
but as prefix only, not infix .
. for functions with multiple param's
of various types: f(x.T1, y.T2, ...)
when an param's type is not given
that means its the same type as
the adt's name;
eg, G: < f(x, y.t), ...>
-- x is type G like so: f(x.G, y.t) .. if num.type has this function:
image().#.char
it means:
image(x.num).#.char .
Labels:
1st-class functions,
adda,
oop
complex apply syntax
3.11: adda/complex apply syntax:
. if functions can return functions,
eg f x x = f(x)(x) = g(x) = y,
what about prefix functions returning biops? eg:
x f(x) y = x g y = g(x,y) .
. need to be careful about where to draw the line between
writer's expressiveness,
and reader's sanity .
. if functions can return functions,
eg f x x = f(x)(x) = g(x) = y,
what about prefix functions returning biops? eg:
x f(x) y = x g y = g(x,y) .
. need to be careful about where to draw the line between
writer's expressiveness,
and reader's sanity .
Labels:
1st-class functions,
adda
macro -- compilation needs context
3.9: adda/macro/compilation needs context:
. when defining macro's that are etrees
rather than text substitutions,
a complication is the context needed:
. a macro is modular, yet it assumes
enough context to be compilable .
. but when does it need compilation?
it could instead have delayed compilation?
. for simplicity, for those reading the code,
you want it to be compilable
at least to the point so that
the etrees being formed are like those that
the reader gets when doing a mental parsing .
. back-end compilation and type-checking
can be done dynamically, at run time .
. when defining macro's that are etrees
rather than text substitutions,
a complication is the context needed:
. a macro is modular, yet it assumes
enough context to be compilable .
. but when does it need compilation?
it could instead have delayed compilation?
. for simplicity, for those reading the code,
you want it to be compilable
at least to the point so that
the etrees being formed are like those that
the reader gets when doing a mental parsing .
. back-end compilation and type-checking
can be done dynamically, at run time .
Labels:
1st-class functions,
adda,
cstr,
macro
2009-12-28
parameter's datatyping
9.6: adda/syntax/signatures:
. perhaps signatures could be in sections,
so that the usual signature is in brief form first:
f.(...).t
. and then there could be details of sideaffects:
eg, (inout: ... out: ...external inout: ...external out: ...)
. also, there needs to be a cap'lang that tells more than
just whether an external is modified or read from .
9.8: adda/syntax/type naming:
. generic types include string (st),
and access modes {out (o), inout(io), const};
. a generic type is expected at end of name,
after the component type that instantiates it:
eg, ch.st.io -- inout char string .
. how are ptr's fiting into this, esp'ly in param's ?
9.11: sci.adda/syntax/inout:
[@] adda/syntax/parameter access modes
. put the {io, o} part of the name on the left: o.x.int ? .
9.12: adda/syntax/parameter access modes:
treat like components
of name can be dot separated and but(/) skip dot
. some other abbrev's can also skip dot:
^ means out;
* seems like arrows in many directions, so it means inout .
.*/.t inout pointer to type"t
.*/.*t inout pointer to inout type"t
instead of out-mode
have an init w default
-- existence of default init
implies not inout just out
. no a default means usu means param not required
it has a default address to out to .
9.26: adda/declaring externals with "<<,,,>>:
. a fun not returning anyting still returns values to externals
-- is a {proc, exe} .
. the syntax can use ada's [danger!-goto`label].sign
to indicate external places the function will "(goto) or affect .
. syntax can have both:
f(x).y <<...>>, f(x).<<...>>
[9.27: proc = << >> --. when enclosing "(all),
defines proc as able to affect any externals .]
10.2: adda/syntax/out.mode:
. use out-mode gets surrounded by << ... >> .
. if the param is a pointer not modified but target is,
f(x/.<<t>>),
else f(<<x/.t>>).
10.15: in-mode:
. instead of access.typing external in.mode's as rom,
there could be separate external's.lists for { in, out}
where in.modes were an extension of the parameter.list
while {inout, out}.modes were an extension of the result type .
eg,
f(x)<<in>>.y <<inout>>`=
'(.(x.t)<<in>>.y`t <<inout>> y`= ...)
notice that in that example,the externals`signature was duplicated
by the {var.decl', literal.description} .
. when the function.symbol is being
initialized by a function.value
rather than listed separately in a
specification part of a library unit,
then some shortcuts can occur:
the symbol need give only param`types,
and the value need give only param`names .
. even if separated into {spec', body},
the function.symbol need list param`names only if
it intends to use them as keywords in calls
(for named parameter association ) .
. the external decl's need be listing only the names
unless the function is a lib'unit
because then there is no context from which to
look up the names and find their types .
10.13: adda/subprogram instantiations:
. recently it was assumed that
constant decl's could be used for indicating
that a parameter was in-mode;
however,
that would be confusing a constant with read-only .
. the first thing a sub'instantiation means
is that the caller is creating
-- and filling in the blanks of --
the sub's act'rec (atleast if it's going to be reentrant) .
named param's:
. even though the act'rec is taking assignments,
so that you might expect sub( formal`= actual ),
named association uses the colon syntax:
sub( formal: actual );
because it follows the pattern of
names being like keys to a map
as used in agg'literals
-- both the structures ( records, arrays ),
and the sets ( dict's, functions ) .
. if the sub' is functional, then there are no side-affects;
and the call can be replaced with the value it returns;
otherwise,
there are 2 forms of side-affects:
* the args can be {out, inout}.mode
* the sub' can access
some external symbols belonging to the caller .
. the out.mode param expects the name of an external:
sub( x: var ) .
(
. notice in.mode pointers expect either
the name of an external symbol
or possibly null if the type allows it .
. given sub( x/.t).c
and the call sub(y.t),
y`address is taken as the pointer value
since the target`type is compatable;
otherwise
the actual arg should be the same type as
the formal parameter .
) .
. the inout.mode param expects
an external that's been assigned a value:
sub( x: var`= init)
-- either before the call
or within it, as shown there .
. if the param is a pointer,
the external modifications can happen on any number of levels
depending on the depth of pointers involved .
. the most common pointer case is bi-level:
sub( x/.t ).t
-- the param is a pointer to a named typed .
. since there are really 2 obj's involved
-- both the pointer and its target --
that means an out.mode type can have
3 cases of side-affects:
{ptr, target, both};
. there are several syntactic candidates for access mode;
some guidelines are:
* the same form used for external accesses
should also be used for out.modes; eg, <<,,,>> .
* the access mode
should be viewed as a specifier,
like the way a function's arg specifies
which image to return:
so then for {out, inout} cases,
it's appending a << >> to the arg`declaration;
and within that sideaffects specifier,
it lists the parameter's affected components
with the default being all components .
eg,
sub( x/.t<< x, x/ >> ).c
-- modifying both the ptr and the ptr`target .eg,
sub( x/.t<<>> ).c
-- this means the same as the example above,since (all components) is the default .
* likewise,
the same syntax can be applied to the return`type;
side-affects are considered a species of return:
eg,
sub( x ).t<< global >> .
. notice that with this syntax,the parameterless symbol can still be declared to be
a subprogram
as the return.type's species is indicating
the program space
which includes the implied parameters:
eg,
p.<< fs >>
-- the sideaffects specifier can be used in place ofa return`type .
*
. the <<>> is specifying {inout, out}
without specifying which one .
. this would be useful for quickly reminding users
that it's ok this hasn't been init'd by the caller,
since the sub is going to be doing it anyway .
*
. within the list of affected components
each one could have a container type of .wo (write-only);
and if no components were specified,
then wo.type could apply to the whole thing:
eg,
sub( x1.t<<wo>>, x2.t<< x`f1.wo >> ).c .
*. conversely, the container.type of rom (read-only mem)
could single out exceptions to the sideaffect.type'ing:
eg,
sub( x.t<< x`f1.rom >> ).c .
10.17: adda/syntax/renaming of externals:. can rename a global to
reuse global's name for local
<< x renamed y, ...>> .
10.20: adda/syntax/templates vs generators:
. to diff' templates from generators, make paren's vs brace:
(.() ... ) -- templates for one expr;
(.{} ...) -- generators;
(.{i} (.{j}, s(i,j) )) -- nested for loop:
the i,j are globally typed but locally redefined
to work the same way math's dummy var's do;
{.() ... } -- template returning a set
like a function returning a function
is returning a set .
. each comma'd section can have a return stmt .
. recursives in math are defined as:
f(x) = { 0 if x=0, otherwise g(x) },
part of adda's mission though
is to have a unified lang that is regular and less ad hoc .
f: (.(x) x?
(0: 0
, others: g(x)
)) -- f is a label for a literal function,
and the set notation is really trying to express a case stmt .
10.22: adda/syntax/renaming implicit param's:
. implicit param's,
where a subroutine expects the caller to have a local symbol
of a symbol that it accesses without going through param's,
can be renamed by the use of labels .
[10.28:
. ie, a label that doesn't have the usual address.types"{loop, jump},
and is instead a value.type that is
labeling another value.type;
that label can be viewed as {renaming, aliasing} what it's labeling .
] .
10.29: adda/syntax/param`typing/run-time vs init-time constraints:
. the param value type
needs both an initial type
and an in-process type
ie, type of var
vs subtype that caller restricts initial value to .
. that is a confusion of the tradition
which is to have an initial value indicate a default value .
. given that the initial value range indicates
an init`type constraint,
then for a syntax that would say
no init is needed,
let one of the init values be null,
and if having no init entails a default,
the syntax would say that like this:
x.t`= (null => default, ...) .
[11.9:
. there is a requirement to
have parameters be like assignments
that is conflicting with the requirement to
hold up contracts .
. the parameter's datatype indicates
the run-time interface expected of it;
however,
the parameter syntax should also have the ability
to require that the client provide
an initial value that is in some proper subset of
the run-time type .
. the simpler way around this conflict
is to declare the parameter's type to be
the initialization's type,
and then assign the parameter to a local symbol
whose type specifies the desired run-time type .
]
adda/syntax/{declared externals, scope blocks, quoted blocks}:
11.21:
. I think the initial concern during this article (started on 11.10)
was how to simplify the syntax for function literals;
ie,
if the scope blocks is .( ... )
and the functional literal is '( ... )
then are there situations where both are needed: '.( ... );
or can a quoted block always refer to a scope block?
no, they are independent:
. commands and functions need not have any locals:
eg, f`= '( ... );
and, expressions with locals need not be quoted:
eg, .( i.int`=0; 1+i) represents the value 1,
not a function literal;
[11.23:
but, what about (.(x) ... )
-- that can only be a function literal, right?
well, it could have a default init to use for eval,
but that would miss the point of the whole construct !
. it says it represents -- not a value --
but a function which happens to also include
mapping the null input .
]
. this brings up the idea that scope blocks
-- whether they are stmt's or expressions --
don't need to declare their externals;
because, they present the reader with no surprises .
. conversely,
if any subexpression can be labeled
-- tagged with a symbol --
then that label can be assigned to a function
(by quoting the label,
so that when the function is called,
it returns an eval of whatever the label refers to) .
f`= 'label .
. if that happens,
any warnings that apply to function bodies,
must also apply to labeled subexpressions .
. doing this causes the eval of f to eval label,
whose return can vary dynamically .
. this is not a problem as long as
f and the label are in the same scope;
whereas, if label is nested in another block:
eg,
f.proc; --. this is external to super's scope block .
super.label:
.( --. this scope block localizes sub.label .
sub.label: (... f`= 'sub); --. possible error .
); f --. error .
. the error here is that a local was assigned to an external,
and then the external was left dangling,
since sub was no longer defined outside of super's scope block .
. here, then, is a case where
there's no need to declare externals,
yet the situation is external-sensitive;
aside from any rules to enforce structured programming
(not jumping into the middle of control structures),
the compiler should be noticing
when external symbols are assigned quoted local labels
or pointers to any other locals;
and, should then check all exec'paths
at the end of the scope block
for whether the external is going to be left with
a dangling reference ?
. a simpler way is to let the
run-time system handle it:
. this could be done by the use of locals as
hidden external pointer variables;
and, when they are not in scope
their pointer is set to void;
so then, trying to eval a void
will raise an exception .
. in this case,
dangling ref's are no problem as long as they aren't used .
. if a function can be assigned to an out.mode parameter,
then it becomes important to know
not only sideaffects,
but also any
readable or exe'able symbols
it expects to find in the caller's scope .
11.22:
. obj's with a lifetime that can go stale include
localized labels or pointers to locals,
and values in local`space {stack, heap} .
. how can adda be free of rules about
assigning locals to externals ?
compile-time checks:
. do a check at the closing of each scope block
or a check at each assignment .
run-time checks:
. use smart pointers that are fully symbolic
so they indicate a pointer`target's valid lifetime:
every pointer includes full path .
. then during run-time,
a pointer can be compared to the current scope path
to see what's available .
. activations of functions and scope blocks
are creating records and record`extensions on the stack .
. scopes are mounted and unmounted
similar to removable drives being
parked in the sys'volumes.folder .
. in unix, everything is represented as a file,
and similarly, adda could have a process.folder,
whose subfolders would represent
all the act'rec's of current programs .
. a record can be seen as a special kind of folder:
one having a fixed number of items:
. a scope block that contains other scope blocks
will have a final item called extensions.record .
. it is either null,
indicating there is no extension currently in effect;
or it's a record containing the current scope block
which may recursively contain nested scope blocks .
. in contrast to this dynamic scope structure
is the static symbol library for the function .
. that is part of the code
so that either the run-time
or the code itself (its template)
can reflect on its own structure .
. the symbol library needs to represent
all possible act'rec ext's simultaniously,
so then they have to be named enumeration:
extension#(1..n).record .
adda/syntax/addressing template vs obj:
. for whether to get template or obj,
have processes and stack be file-based;
this is how a cli [cmd line interface]
works a scope block:
make and go to a subdir,
where the subdir is an act'rec`ext .
. an active function has both a template
that is constant
and an activation record (act'rec)
that is variable
(it's varying relative to the template
-- a parameterized template needs ram
even to hold a constant value
since that will be varying across
template instantiations ) .
. the template is often called a function literal,
while the function object (template instantiated with act'rec)
is called a closure .
[12.24: a function literal may optionally be a template
depending on whether it needs to be
instantiated with act'rec .]
. a complexity when dealing with function assignments
is that
their values can be either templates
or partially active objects;
eg, a subroutine literal is implicitely
taking as a parameter
the variables it's using from the enclosing scope .
. a symbol literal (eg, f`= 'L.label)
is [12.24: virtually refering to a variable pointer?
(this thought was forgotten)]
. by supporting first-class functions,
adda is recognizing that a function.variable
can refer to both the objects in a process,
and to the same code in its inactive template form .
. a first-class function is concerned with
not only eval'ing but constructing functions,
so it can point at parts it can't eval'
and there's a fine line with the use of
pointer to function .
. does the function point to obj or template ?
. lisp's idea of a closure
is an obj' vs symbolic closure .
. obj'closures are concerned with
keeping a function eval'able
even after its been removed from environs which
defined some of its values;
so, it replaces any such external var's
with the current value of the var .
. the symbolic closure is not concerned with
being eval'able:
it needs instead to replace ref's to externals
with refs to param's .
. keep in mind lang priorities too:
first create a simple way to do
the simple things -- what c and pascal do --
in a syntax that will still apply for the complex later .
pos"simplification:
. the simple case is concerned only with
function eval not composition
it should also make it easier to write in the current lang
(obj-c with cocoa lib's) .
12.14: adda/syntax/return:
. return could be a multi-operation obj':
representing the variable being returned
when used with assignment: return`= val;
and, representing the exit subprogram command
when given without param's: return .
. it should be building on the usual symantics for symbols
rather than creating special cases;
and assignment to a function usually means changing its function .
. stay with what's actually going on
so then people can easily remember it just by knowing
what returns and symbols are .
. the return is an implicit out.mode var' .
. "(y) is well known in math function y= f(x);
if symbol "(return) was reserved as the return var,
then instead of having a return stmt,
there could be drop out design as in pascal;
but since that is good structure whipping good ergonomics,
the exit could be reused:
(exit subprogram) instead of (exit loop name) .
. what subprogram is called exactly
would depend on how an anonymous function refers to itself:
. if it's nested then it may call itself sub,
otherwise it's self .
. whatever the name, there are 3 entities it can return from:
the immediate function, the enclosing function, or the caller .
. oop argues about whether it's agent or function that is self,
perhaps the words to use would be self.scope, super.scope .
Labels:
1st-class functions,
adda,
functional,
param's,
rom,
syntax,
type,
wo
2009-12-27
funarg problem resolution
8.29: adda/1st-class functions/funarg problem resolution:
. the 1st-class function is said to involve the funarg problem;
for example,
the lisp`closure handles externals for the funarg problem
by replacing references to externals
with var's initilized with the external's current value .
. but, I'm thinking of 1st-class as meaning
that the function considers its value
to be the algorithm it was assigned .
. a function's type includes its permutation of inout types;
where this permutation includes more than its signature (input, output),
but also its expected externals .
. externals would work like file accesses:
when it came time to instantiate the funtion,
the caller would be expected to have a local whose name
matched the name of external being expected .
[12.19: in summary:
. the main issue was how to share code that is
dependent on the source context .
. the typical half-hearted way is to initialize the dependencies
with the current values;
whereas the 1st-class way is to just consider the dependencies to
like generics parameters .
]
. a separate issue is desiring to change algorithm values
by partially instantiating them;
(eg, f(x)`= g(x, x2=c)) .
9.27: adda/syntax/1st-class functions:
. what was the confusion about functions ?
if not declared using arg may need f`body or f`map;
otherwise, it works like ptr:
f(x)`=
f`=
.
11.12: adda/referring to caller:
. in a reflective system with first-class functions
the anon'code may want to know who called it;
is there always such a symbolic path?
yes:
because it cannot be evoked without referring to that path .
[you could have a request to call
all proc's in a random tree,
so the path could involve a lot of trivia .
. or it could look like
a lot of code was coming from the same symbol
if it was a pointer traversing a tree of code . ]
. what if wanting generic :
if (path)`type is fun`type
then the (path) @ (arg);
[12.24: the conventional use for @ is key@set
so then for calls, arg@function
]
. a function's type includes
not only arg and return type,
but also inout modes and expected externals .
Labels:
1st-class functions,
adda
Subscribe to:
Posts (Atom)