effect propagation

2 views
Skip to first unread message

John Nowak

unread,
Nov 5, 2007, 7:19:10 AM11/5/07
to catla...@googlegroups.com
I'm not sure if this has been discussed before (a search revealed
nothing), but I'm curious if there are plans to handle effects in Cat
on the type level. For example, a function that does not have a side
effect might have the type A -> A, but one that does might have the
type A ~> A.

Handling effects as such is desirable so you can isolate effectful
code, but it seems rather complicated to implement. Take the following
functions (forgive me for always using explicit stack variables):

apply :: A (A -> B) -> B
compose :: A (B -> C) (C -> D) -> A (B -> D)

Apply will have an effect if the top value of the stack is a function
that will have an effect. Compose, however, will never have an effect.
It will though put a function on the top of the stack that will have
an effect when applied if either of the two functions on top of the
stack when compose is called will have an effect when applied.

It seems one way to handle this would be to provide some way of
associating function types. Let a single-tick indicate that if that
particular function is determined to have an effect, than all others
with a single tick will have an effect as well. For example:

apply :: A (A '-> B) '-> B
compose :: A (B '-> C) (C '-> D) -> A (B '-> D)

Multiple ticks can be used for even more complicated situations. For
example, imagine a function that assumes three functions on the stack.
Assume it composes the bottom two under the top, then evaluates the
top function with the newly composed function off the stack, then
returns the composed function to the top. It would have this type:

[ compose ] dip dip :: A (B '-> C) (C '->D) (A ''->E) ''-> E (B '-> D)

These have been my initial thoughts on the topic. I'm curious if
anything similar has been proposed previously as I'm currently working
on a typed concatenative language and would like to incorporate such a
system.

- John

Christopher Diggins

unread,
Nov 5, 2007, 10:29:52 AM11/5/07
to catla...@googlegroups.com
On 11/5/07, John Nowak <jo...@johnnowak.com> wrote:
>
> I'm not sure if this has been discussed before (a search revealed
> nothing), but I'm curious if there are plans to handle effects in Cat
> on the type level. For example, a function that does not have a side
> effect might have the type A -> A, but one that does might have the
> type A ~> A.

That is exactly what I do (though it isn't yet handled very well by
the Cat interpreter).
See: http://www.cat-language.com/manual.html

I call "effectful code" impure, but the idea is the same.

> Handling effects as such is desirable so you can isolate effectful
> code, but it seems rather complicated to implement. Take the following
> functions (forgive me for always using explicit stack variables):
>
> apply :: A (A -> B) -> B
> compose :: A (B -> C) (C -> D) -> A (B -> D)
>
> Apply will have an effect if the top value of the stack is a function
> that will have an effect. Compose, however, will never have an effect.
> It will though put a function on the top of the stack that will have
> an effect when applied if either of the two functions on top of the
> stack when compose is called will have an effect when applied.
>
> It seems one way to handle this would be to provide some way of
> associating function types. Let a single-tick indicate that if that
> particular function is determined to have an effect, than all others
> with a single tick will have an effect as well. For example:
>
> apply :: A (A '-> B) '-> B
> compose :: A (B '-> C) (C '-> D) -> A (B '-> D)

I don't think that this labeling is neccessary. The rules can be
described formally, and then tracked by your implementation, the ticks
can be inferred by the rules. I just parameterize all function types
with a boolean value.

> Multiple ticks can be used for even more complicated situations. For
> example, imagine a function that assumes three functions on the stack.
> Assume it composes the bottom two under the top, then evaluates the
> top function with the newly composed function off the stack, then
> returns the composed function to the top. It would have this type:
>
> [ compose ] dip dip :: A (B '-> C) (C '->D) (A ''->E) ''-> E (B '-> D)
>
> These have been my initial thoughts on the topic. I'm curious if
> anything similar has been proposed previously as I'm currently working
> on a typed concatenative language and would like to incorporate such a
> system.

Other approaches (which you are probably aware of) include unqiueness
typing and monads.

I'm looking forward to hearing more about your language.

- Christopher

John Nowak

unread,
Nov 5, 2007, 10:04:22 PM11/5/07
to catla...@googlegroups.com

On Nov 5, 2007, at 10:29 AM, Christopher Diggins wrote:

>> apply :: A (A '-> B) '-> B
>> compose :: A (B '-> C) (C '-> D) -> A (B '-> D)
>
> I don't think that this labeling is neccessary. The rules can be
> described formally, and then tracked by your implementation, the ticks
> can be inferred by the rules. I just parameterize all function types
> with a boolean value.

I didn't mean to say that it is necessary to show such labels in the
type when presenting it to the user. (That said, I don't think it's a
bad idea, and I would personally show them.) It does seem though that
such an approach would at least be necessary under the hood if you
want to be able to do it with complete accuracy. Perhaps that's what
you were saying, and were just simply suggesting against the noise in
the type presentation.

The other approach I've come up with is having multiple versions of
functions as such:

apply :: A (A -> B) -> B

apply~ :: A (A ~> B) ~> B

This technically works, but you'll run into issues with having to
change function implementations if you change their inputs. That's the
sort of issue you can run into with languages like Haskell that must
be avoided.

> Other approaches (which you are probably aware of) include unqiueness
> typing and monads.

Uniqueness types seem unnecessary. After all, in a linear language (is
Cat truly linear?), all data should be unique by virtue of the dynamic
semantics. Likewise, all functions in a concatenative language are
technically monadic anyway. The issue here isn't making effectful code
possible, as it is in Haskell, but simply identifying effectful code
for documentation and optimization purposes.

- John

Christopher Diggins

unread,
Nov 7, 2007, 9:04:24 PM11/7/07
to catla...@googlegroups.com
On Nov 5, 2007 10:04 PM, John Nowak <jo...@johnnowak.com> wrote:
>
>
> On Nov 5, 2007, at 10:29 AM, Christopher Diggins wrote:
>
> >> apply :: A (A '-> B) '-> B
> >> compose :: A (B '-> C) (C '-> D) -> A (B '-> D)
> >
> > I don't think that this labeling is neccessary. The rules can be
> > described formally, and then tracked by your implementation, the ticks
> > can be inferred by the rules. I just parameterize all function types
> > with a boolean value.
>
> I didn't mean to say that it is necessary to show such labels in the
> type when presenting it to the user. (That said, I don't think it's a
> bad idea, and I would personally show them.) It does seem though that
> such an approach would at least be necessary under the hood if you
> want to be able to do it with complete accuracy.

Yes.

> Perhaps that's what
> you were saying, and were just simply suggesting against the noise in
> the type presentation.

I was sidestepping the issue of implementation. I also got confused
because of the multiple notations, you presented. I was arguing
against multiple notations, but the "~>" label I agree with.

> The other approach I've come up with is having multiple versions of
> functions as such:
>
> apply :: A (A -> B) -> B
> apply~ :: A (A ~> B) ~> B
>
> This technically works, but you'll run into issues with having to
> change function implementations if you change their inputs. That's the
> sort of issue you can run into with languages like Haskell that must
> be avoided.

I believe one work around in Haskell is type-classes.

> > Other approaches (which you are probably aware of) include unqiueness
> > typing and monads.
>
> Uniqueness types seem unnecessary. After all, in a linear language

> (is Cat truly linear?

No.

>), all data should be unique by virtue of the dynamic
> semantics. Likewise, all functions in a concatenative language are
> technically monadic anyway.

I am not sure I see how that is. I can see that you can use monads to
implement a concatenative language, but sequencing operations is not
mandatory.

> The issue here isn't making effectful code
> possible, as it is in Haskell, but simply identifying effectful code
> for documentation and optimization purposes.

Yes I agree.

>
> - John

Are you aware of the Concatenative mailing list at
http://tech.groups.yahoo.com/group/concatenative/ John?

I mention this because they will be interested in your ideas and work.

- Christopher

tom.got...@gmail.com

unread,
Nov 7, 2007, 9:22:54 PM11/7/07
to catla...@googlegroups.com

> > > Other approaches (which you are probably aware of) include unqiueness
> > > typing and monads.
> >
> > Uniqueness types seem unnecessary. After all, in a linear language
>
> > (is Cat truly linear?
>
> No.
>

sorry to jump in like that, but could it be? meaning is there a point
where you absolutely need non-linearity?

(i'm interested because this is a major point of difficulty i have in
Packet Forth: it's linear, with ad-hoc non-managed pointers to fill op
some gaps like global variables)

John Nowak

unread,
Nov 7, 2007, 11:06:32 PM11/7/07
to catla...@googlegroups.com

On Nov 7, 2007, at 9:04 PM, Christopher Diggins wrote:

> I was sidestepping the issue of implementation. I also got confused
> because of the multiple notations, you presented. I was arguing
> against multiple notations, but the "~>" label I agree with.

To be clear, the single quotes for expressing dependency are in
addition to ~>. For example, apply has type (A (A '->B) '-> B), and
display has the type (A a ~> A a). You only need quotes for when a
function may or may not have side effects depending on what the stack
is when it is called. Apologies if I'm restating the obvious.

>> (is Cat truly linear?
>
> No.

Any reason why not? I suppose it isn't worth pursuing perhaps if
you're using an existing runtime that handles collection anyway. It
does present some interesting design challenges however (and I think I
should have some interesting solutions to show soon).

> I am not sure I see how that is. I can see that you can use monads to
> implement a concatenative language, but sequencing operations is not
> mandatory.

All functions are monadic because they all take a stack as input and
return a stack as output, and the stack is threaded throughout the
program. In the program 'a b c', b has a data dependency on the result
of a, and c has a dependency on the result of b.

To draw a comparison to the IO monad in Haskell, it's easy to imagine
a "world value" on top of the stack (that most words operate below,
but some words read/update) that is threaded throughout the entire
program.

This is why, I believe, that Joy is considered a purely functional
language. One great thing about linear concatenative languages is that
they're both purely functional and allow efficient O(1) data
structures to be implemented via mutation.

> Are you aware of the Concatenative mailing list at
> http://tech.groups.yahoo.com/group/concatenative/ John?
>
> I mention this because they will be interested in your ideas and work.

Yes, I'm on the list, but I've not posted yet. I'm waiting until I
have a bit more to share.

Thanks for the replies.

- John

Christopher Diggins

unread,
Nov 8, 2007, 10:46:41 AM11/8/07
to catla...@googlegroups.com
On Nov 7, 2007 9:22 PM, <tom.got...@gmail.com> wrote:
>
>
> > > > Other approaches (which you are probably aware of) include unqiueness
> > > > typing and monads.
> > >
> > > Uniqueness types seem unnecessary. After all, in a linear language
> >
> > > (is Cat truly linear?
> >
> > No.
> >
>
> sorry to jump in like that, but could it be? meaning is there a point
> where you absolutely need non-linearity?

Wait a second. I take back what I said, I think Cat is linear. There
is not sharing of data at the current time. Lists (i.e. collections)
are copied whenever "dup" is called, and are freed whenever "pop" is
called. Similarly "apply" disposes of the data automatically.

I have yet introduced heap memory management though, which will
introduce pointers (aka references or aliases) into the language.
With aliases, will it still be linear? The pointer can't be shared,
but what it points to can be shared.

Global variables are an interesting problem, because I want to add
them to Cat as well, in order to implement module-like behaviour.
I thought it packet-forth (or is it CAT) where you would pass global
variables on the top of the stack, dipping every instruction below it?
Wouldn't that satisfy the constraint of linearity?

- Christopher

Christopher Diggins

unread,
Nov 8, 2007, 11:05:22 AM11/8/07
to catla...@googlegroups.com
On Nov 7, 2007 11:06 PM, John Nowak <jo...@johnnowak.com> wrote:
>
>
> On Nov 7, 2007, at 9:04 PM, Christopher Diggins wrote:
>
> > I was sidestepping the issue of implementation. I also got confused
> > because of the multiple notations, you presented. I was arguing
> > against multiple notations, but the "~>" label I agree with.
>
> To be clear, the single quotes for expressing dependency are in
> addition to ~>. For example, apply has type (A (A '->B) '-> B), and
> display has the type (A a ~> A a). You only need quotes for when a
> function may or may not have side effects depending on what the stack
> is when it is called. Apologies if I'm restating the obvious.

Oh, okay.

> >> (is Cat truly linear?
> >
> > No.
>
> Any reason why not?

I take back what I said, see my earlier response to Tom.

> I suppose it isn't worth pursuing perhaps if
> you're using an existing runtime that handles collection anyway. It
> does present some interesting design challenges however (and I think I
> should have some interesting solutions to show soon).

I look forward to it.

> > I am not sure I see how that is. I can see that you can use monads to
> > implement a concatenative language, but sequencing operations is not
> > mandatory.
>
> All functions are monadic because they all take a stack as input and
> return a stack as output, and the stack is threaded throughout the
> program. In the program 'a b c', b has a data dependency on the result
> of a, and c has a dependency on the result of b.

Hmmm.... I'll be perfectly honest and admit I am not totally
comfortable with the definition of monads and what constitutes being
monadic. I always understood "monadic" as implying a mandatory
sequencing of operations. Is this correct? Instructions in a
concatenative language do not have to be evaluated in sequence: "1 2 +
3 4 +" could be evaluated left to right, or could be split into two
evaluations: "1 2 +" and "3 4 +".

While there are clearly data flow dependencies introduced whenever you
compose functions, it seems counter-intuitive to me to say that that
is "monadic". If I was to compose "f" with "g" with "h" (f . g . h)
regardless of what input and output they had, there would be a "data
dependency". So I have to infer by what you are saying that function
composition is monadic. This seems suspect, and introduces murkiness.
From a mathematical standpoint, I don't need to use words like
"monad", to understand function composition.

> To draw a comparison to the IO monad in Haskell, it's easy to imagine
> a "world value" on top of the stack (that most words operate below,
> but some words read/update) that is threaded throughout the entire
> program.

That is a valid approacg. See
http://pied.mine.nu/index.php?page=Lambda&id=22 for an example.
However, it is not neccessary, we can use more mundane techniques.

Alternatively we can implement Cat without monads in Haskell
http://groups.google.com/group/catlanguage/browse_thread/thread/1cd20cee5a087509
This shows that monads are not neccessary for implementing Cat (and
probably Joy).

> This is why, I believe, that Joy is considered a purely functional
> language.

The "purely functional" definition is hard to pin down. I have never
been able to track down a satisfactory definition, other than if it is
Haskell, then it is purely functional. There is a paper on the
subject, but I seem to remember it kind of meandered around the
subject, and started with the assumption that "Haskell is purely
functional". Kind of silly if you ask me.

> One great thing about linear concatenative languages is that
> they're both purely functional and allow efficient O(1) data
> structures to be implemented via mutation.

Interesting, I never really thought about the advantages in that way.

> > Are you aware of the Concatenative mailing list at
> > http://tech.groups.yahoo.com/group/concatenative/ John?
> >
> > I mention this because they will be interested in your ideas and work.
>
> Yes, I'm on the list, but I've not posted yet. I'm waiting until I
> have a bit more to share.

I like to encourage people to post often and early.

> Thanks for the replies.

My pleasure, thanks for the discussion.

- Christopher

John Nowak

unread,
Nov 10, 2007, 12:24:47 AM11/10/07
to catla...@googlegroups.com

On Nov 8, 2007, at 10:46 AM, Christopher Diggins wrote:

> I have yet introduced heap memory management though, which will
> introduce pointers (aka references or aliases) into the language.
> With aliases, will it still be linear? The pointer can't be shared,
> but what it points to can be shared.

No, it would not be linear in this case. Say you have a pointer to
some foo, and then you pop foo from the stack. If you expect the
pointer to still be valid (I assume you don't want dangling pointers),
you can't let pop free foo.

If foo is not a collection -- perhaps it is just a file handle or a
number or some other atomic value-- you can get by with reference
counting. This way, pop simply decrements the count and frees if it is
zero, and you keep deterministic freeing. If you allow pointers to any
type of value, you need a full blown collector, and any cleanup needs
to be handled as part of finalization.

I'm currently using reference counting so that files can be duplicated
and only closed when the last "copy" is removed from the stack. Each
value contains a pointer to a struct of functions, one of which
handles popping for that specific type. Pop simply calls this
function. The alternative to reference counting files would be
introducing some form of "undupable type" to prevent multiple
references to the same file from ever being created.

> Global variables are an interesting problem, because I want to add
> them to Cat as well, in order to implement module-like behaviour.
> I thought it packet-forth (or is it CAT) where you would pass global
> variables on the top of the stack, dipping every instruction below it?
> Wouldn't that satisfy the constraint of linearity?

Yes, provided you copy the global variable each time you access it.
I'm doing something along those lines. It's very handy for dealing
with arithmetic, where you're only copying a handful of bytes (4 or 8
plus any boxing involved).

- John

Christopher Diggins

unread,
Nov 10, 2007, 12:32:01 AM11/10/07
to catla...@googlegroups.com
On Nov 10, 2007 12:24 AM, John Nowak <jo...@johnnowak.com> wrote:
>
>
> On Nov 8, 2007, at 10:46 AM, Christopher Diggins wrote:
>
> > I have yet introduced heap memory management though, which will
> > introduce pointers (aka references or aliases) into the language.
> > With aliases, will it still be linear? The pointer can't be shared,
> > but what it points to can be shared.
>
> No, it would not be linear in this case. Say you have a pointer to
> some foo, and then you pop foo from the stack. If you expect the
> pointer to still be valid (I assume you don't want dangling pointers),
> you can't let pop free foo.

I am a bit on the fence about whether I want dangling pointers. They
can be useful if I want to move Cat more towards an assembly language
where memory management has to be explicit.

> If foo is not a collection -- perhaps it is just a file handle or a
> number or some other atomic value-- you can get by with reference
> counting. This way, pop simply decrements the count and frees if it is
> zero, and you keep deterministic freeing. If you allow pointers to any
> type of value, you need a full blown collector, and any cleanup needs
> to be handled as part of finalization.

Yes.

> I'm currently using reference counting so that files can be duplicated
> and only closed when the last "copy" is removed from the stack. Each
> value contains a pointer to a struct of functions, one of which
> handles popping for that specific type. Pop simply calls this
> function. The alternative to reference counting files would be
> introducing some form of "undupable type" to prevent multiple
> references to the same file from ever being created.

Not a bad idea the undupable type.

> > Global variables are an interesting problem, because I want to add
> > them to Cat as well, in order to implement module-like behaviour.
> > I thought it packet-forth (or is it CAT) where you would pass global
> > variables on the top of the stack, dipping every instruction below it?
> > Wouldn't that satisfy the constraint of linearity?
>
> Yes, provided you copy the global variable each time you access it.
> I'm doing something along those lines. It's very handy for dealing
> with arithmetic, where you're only copying a handful of bytes (4 or 8
> plus any boxing involved).
>
> - John

- Christopher

John Nowak

unread,
Nov 10, 2007, 1:09:09 AM11/10/07
to catla...@googlegroups.com

On Nov 8, 2007, at 11:05 AM, Christopher Diggins wrote:

> Hmmm.... I'll be perfectly honest and admit I am not totally
> comfortable with the definition of monads and what constitutes being
> monadic. I always understood "monadic" as implying a mandatory
> sequencing of operations. Is this correct?

Monads do introduce sequencing, yes.

> Instructions in a concatenative language do not have to be evaluated
> in sequence: "1 2 + 3 4 +" could be evaluated left to right, or
> could be split into two evaluations: "1 2 +" and "3 4 +".

It depends. If you define everything as a function that takes a stack
as an argument, as I am, you have no choice but to evaluate in sequence.

You can throw out the stack altogether. Such a language would need
some way of explicitly sequencing effects, as functions would no
longer be monadic, and hence not implicitly sequenced. For example, if
you can evaluate 3 4 + first, then 3 is no longer a function of type
( -> int), and + is now a function that takes two independent values
instead of a stack of values as an argument.

You could also have a language with multiple stacks with (possibly
concurrent) evaluation of sub-functions that operate on empty stacks.
Evaluation would, assumedly, be directed by the type system. In such a
language, the sub-functions being evaluated are monadic, but the
larger program isn't. As a result, you still need a way to explicitly
sequencing sub-functions. The sub-functions themselves however do not
need any means of explicit sequencing as they're monadic.

> So I have to infer by what you are saying that function composition
> is monadic.

I'm only saying that composition of two monadic functions yields a new
monadic function, and that all functions in a stack-to-stack language
are monadic. This doesn't seem to hold for all concatenative languages
however as I've shown above, although I'm not sure I'd even call such
languages concatenative. That probably isn't a very interesting
discussion...

>> To draw a comparison to the IO monad in Haskell, it's easy to imagine
>> a "world value" on top of the stack (that most words operate below,
>> but some words read/update) that is threaded throughout the entire
>> program.
>
> That is a valid approacg. See
> http://pied.mine.nu/index.php?page=Lambda&id=22 for an example.
> However, it is not neccessary, we can use more mundane techniques.

Of course. I was just suggesting you can conceptualize this world
value as a means for explaining the mandatory sequencing of effectful
functions.

> Alternatively we can implement Cat without monads in Haskell. This

> shows that monads are not neccessary for implementing Cat (and
> probably Joy).

Monads aren't necessary for implementing Haskell either.

>> This is why, I believe, that Joy is considered a purely functional
>> language.
>
> The "purely functional" definition is hard to pin down. I have never
> been able to track down a satisfactory definition, other than if it is
> Haskell, then it is purely functional. There is a paper on the
> subject, but I seem to remember it kind of meandered around the
> subject, and started with the assumption that "Haskell is purely
> functional". Kind of silly if you ask me.

Purely functional just means referential transparency. If you call
some function (a a -> a) twice with identical values on top of the
stack, you'll get the same result. Joy works this way.

Obviously this isn't the case if something like IO is involved. This
is why you need to conceptualize that the world is passed on the
stack. You can call the function twice, but the second time you call
it, it is being passed the modified world variable from the first
call. Accordingly, it can return a different result without violating
referential transparency.

It seems somewhat like hand waving perhaps, but it is no different
than what Haskell does with the IO monad. If Joy isn't purely
functional, then Haskell isn't either.

- John

Tom Schouten

unread,
Nov 11, 2007, 5:53:28 PM11/11/07
to catla...@googlegroups.com
> Global variables are an interesting problem, because I want to add
> them to Cat as well, in order to implement module-like behaviour.
> I thought it packet-forth (or is it CAT) where you would pass global
> variables on the top of the stack, dipping every instruction below it?
> Wouldn't that satisfy the constraint of linearity?

CAT (le mien) which is really scheme with different syntax, uses
shared data structures. this makes all kinds of 'undo' operations more
efficient (error handling, backtracking, ...) so i use them a lot.

i'm using a dipped dictionary indeed. if you allow this for every word,
you really get imperative programming, i.e. you're managing state all the time..
(if think of the entire machine state as a value that is threaded from function
to function, you have a nice pure FP model of assembly code :)

so i use this only for the high level "control" section of the forth
compiler/interaction system, which acts as a database for the purely
functional,
utility words, which operate only on the stack.

the problem i have with Packet Forth is to implement variables efficiently
(without a huge amount of copying). this seems to be really impossible
to me.. values are easy: they can be lazily copied using reference counting.
the bulk of my data is in abstract containers not accessible in the language.
(i.e. image frames). lists are copied, but 'map' and 'for-each' have optimized
implementations.

storage boxes are different. PF has pointers, which are used
in low-level methods, and can address any box (list/stack cell) on one of the
3 stacks (data, return, allot stack). pointers to the allot stack
(global variables) are
safe since they are permanent (create only). pointers to data and return
stack are managed only in lowlevel code, and so somewhat isolated.
this works, but
is a bit dirty.. my plan is to use some kind of barrier between safe
and unsafe code later..


Re: purely functional

it seems indeed there's no real definition of purely functional, but what
i read a lot is the term "value oriented programming". for me purely FP = no
assignments. if you're juggling with a settable dictionary or a large
monad where you can poke around randomly, you're using imperative programming
"locally" even in a pure language.

Tom Schouten

unread,
Nov 11, 2007, 6:03:52 PM11/11/07
to catla...@googlegroups.com
> I'm currently using reference counting so that files can be duplicated
> and only closed when the last "copy" is removed from the stack. Each
> value contains a pointer to a struct of functions, one of which
> handles popping for that specific type. Pop simply calls this
> function.

same in Packet Forth. it seems obvious in retrospect, but was kind of a
revelation to me that 'drop' actually means free() possibly with refcount, and
that in a stack language, it's hard to forget to drop stuff!

> The alternative to reference counting files would be
> introducing some form of "undupable type" to prevent multiple
> references to the same file from ever being created.

i use these in PF too. this leads to 2 classes of objects: those that are
essentially shared (i call them accumulators) and those that are distinct,
where you would use copy-on-write. (in PF all image operations are
pure in this sence: they never modify input data, but all drawing operations
are accumulative: allways modify the object in-place).

>
> > Global variables are an interesting problem, because I want to add
> > them to Cat as well, in order to implement module-like behaviour.
> > I thought it packet-forth (or is it CAT) where you would pass global
> > variables on the top of the stack, dipping every instruction below it?
> > Wouldn't that satisfy the constraint of linearity?
>
> Yes, provided you copy the global variable each time you access it.
> I'm doing something along those lines. It's very handy for dealing
> with arithmetic, where you're only copying a handful of bytes (4 or 8
> plus any boxing involved).

in PF (sorry for the me-too-ness if my post..) i have an operator '@>'
which is like Forth's fetch '@' but _moves_ data from a variable to the
data stack. i use this a lot: it amazes me how many times you really
don't need the copying.

Tom Schouten

unread,
Nov 11, 2007, 6:07:52 PM11/11/07
to catla...@googlegroups.com
>
> I am a bit on the fence about whether I want dangling pointers. They
> can be useful if I want to move Cat more towards an assembly language
> where memory management has to be explicit.
>

maybe it is possible to use some kind of 'taint' notion in the type system to
create a barrier between safe and unsafe code? i'm not sure wether this
makes any sense at all, i don't know much about type theory..

Tom Schouten

unread,
Nov 11, 2007, 6:15:07 PM11/11/07
to catla...@googlegroups.com
> All functions are monadic because they all take a stack as input and
> return a stack as output, and the stack is threaded throughout the
> program. In the program 'a b c', b has a data dependency on the result
> of a, and c has a dependency on the result of b.
>

calling this "monadic" is a bit dangerous i think. i did so myself for a while,
but i think it deserves a different terminology, leaving the word "monad"
for that thing that supports the operations "bind" and "unit" obeying the
monad laws.

John Nowak

unread,
Nov 11, 2007, 11:12:34 PM11/11/07
to catla...@googlegroups.com

On Nov 11, 2007, at 6:03 PM, Tom Schouten wrote:

> same in Packet Forth.

> i use these in PF too.

Glad we're on the same track!

> in PF (sorry for the me-too-ness if my post..) i have an operator '@>'
> which is like Forth's fetch '@' but _moves_ data from a variable to
> the
> data stack. i use this a lot: it amazes me how many times you really
> don't need the copying.

Aye. This is my reason for using extensible records in my language-in-
progress (Dequote); You can remove an item from a record and encode
this on the type level via "lacks predicates". Without the ability to
deconstruct and extend records field by field, you'd need to copy out
of some predefined struct type instead. This need to avoid copying has
shaped the type system considerably.

I'm trying to get the time to go through some of your papers at the
moment. I learned to program using Max and Pure Data, and have used
Max extensively, so I'm naturally interested in what you're doing.

- John

John Nowak

unread,
Nov 11, 2007, 11:16:59 PM11/11/07
to catla...@googlegroups.com
On Nov 11, 2007, at 6:15 PM, Tom Schouten wrote:

> calling this "monadic" is a bit dangerous i think. i did so myself
> for a while,
> but i think it deserves a different terminology, leaving the word
> "monad"
> for that thing that supports the operations "bind" and "unit"
> obeying the
> monad laws.

It could be argued that composition in such stack-based languages is
analogous to bind. I'm certainly not the first person to suggest this.

- John

Christopher Diggins

unread,
Nov 11, 2007, 11:39:30 PM11/11/07
to catla...@googlegroups.com
Some interesting comments here:
http://programming.reddit.com/info/25liu/comments/
Reply all
Reply to author
Forward
0 new messages