|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
| < Prev | 1 - 2 - 3 - 4 - 5 | Next > |
|
|
sweetening concatenative syntaxI've had some thoughts recently on syntactic additions to
concatenative languages that seem potentially quite useful. At the very least, they would put an end to silly discussions over largely imagined deficiencies of postfix syntax and pointfree programming. This is perhaps crucial if we expect any significant uptake of concatenative languages. Below are the four extensions that I'm proposing. I'm strongly considering one or more in the language I'm currently working on (named "Fifth" for what are likely obvious reasons). The first two should be fairly uncontroversial. The latter two are simple translations I've not seen discussed before that seem potentially very useful in practice. I. Lambda Expressions Assuming functions have the syntax '[<body>]', it seems useful to introduce the syntax '[<bindings> -> <body>], where bindings are ordered with the top of the stack towards the right as is familiar. For example, the following two functions are equivalent: foo :: -> [a b -> b a a] foo = [swap dup] foo = [a b -> b a a] Note that the type syntax mimics the lambda expression syntax (or vice versa if you prefer). The type notation is similar to Cat's with minor alterations for the purposes of brevity. In particular, scalar variables are all lowercase, row variables are all uppercase, and concrete types are title-case and of at least two characters (to avoid confusion with row variables). Variables should, of course, be lexically scoped. A translation of expressions with lambdas to efficient pointfree stack-based code is not especially difficult. This is the case regardless of if the language is linear (which introduces only small complications), typed, or "lacking" a retain stack. Of course, I elide the translation here for the sake of... space. II. Local Function Variables If you permit lambdas, it makes sense to offer a simple syntax for declaring functions with named variables. This is similar to how Scheme offers '(define (foo <bindings>) <body>)' to mean '(define foo (lambda (<bindings>) <body>))'. The declaration syntax proposed here mimics use. In particular, the name of the function being defined occurs *after* the arguments. The following two statements are equivalent (where 'i' is the identity combinator with the type 'A (A -> B) -> B'): a b foo = b a a foo = [a b -> b a a] i Here's another example in which 'unlist' is a deconstructor for a list; the first function provided handled the null case and the second handles the cons case: unlist :: A [b] (A -> C) (A b [b] -> C) -> C map :: [a] (a -> b) -> [b] list f map = list [] [x xs -> x f i xs f map cons] unlist It should be noted that both lambda expressions and functions declared with the local variable syntax may use more items on the stack than they explicitly bind. For example, the following definition of map is equivalent to the above and likely preferable in practice: f map = [] [x xs -> x f i xs f map cons] unlist III. Prefix Notation It occurred to me recently that there exists a simple syntactic translation from prefix code (a la Scheme), where '(foo a b c)' is the application of 'foo' to three arguments, to postfix code. This translation can be done without any type information. The translation consists of simply removing the parenthesis and placing the first element at the end. If that first element is a local binding or a lambda expression, an 'i' is prepended to cause it to be evaluated. Here are some simple translation examples: (cons 1 null) => 1 null cons (+ (- 1 2) 3) => 1 2 - 3 + [f -> (f 10)] => [f -> 10 f i] f foo = (f 5) => f foo = 5 f i Interestingly, you get partial application for free: double = (* 2) One thing that may seem like a problem is that '(1 2 3)' will be translated to '(2 3 1)' when really an error should occur as '1' is not a function. However, that's not the case: '1' *is* a function. More precisely, it is a row polymorphic function that consumes a stack and yields a new stack (1 :: A -> A int). As such, the above syntactic translation is completely valid and it would be wrong to reject it. Prefix notation may seem like a curiosity at first, perhaps existing only to lure over those familiar with prefix notation. However, I'd argue that prefix notation makes certain code objectively easier to read. This is especially the case when dealing with deconstructors like 'if' or 'unlist' as the higher order function of primary interest is "announced" earlier in the definition. In the following example, both functions are equivalent: f map = [] [x xs -> x f i xs f map cons] unlist f map = (unlist [] [x xs -> x f i xs f map cons]) (Perhaps this is not the best example. Substitute a better one with nested ifs.) Prefix notation also has the benefit that you can express "nested" code (as above) in a way that allows editors to automatically intent properly. This is not at all the case with purely postfix code where type information and perhaps some heuristics would need to be involved to produce acceptable indentation. Here's a rewriting of map using *only* prefix notation in a way that most any Scheme or Haskell programmer would find comfortable: f map = (unlist [] [x xs -> (cons (f x) (map xs f))]) IV. Indentation Prefix notation is often criticized for being overly verbose or noisy. The Python solution is to use indentation instead of paired delimiters, but this introduces a number of problems: It's harder for machines to generate valid code, pasting between sources can be messy, editors can't really automatically re-indent code, plenty of people (myself included) hate it, etc. The correct way to address this problem (if you are to address it at all) is to do what Haskell does and offer *optional* indentation- sensitive syntax that gets translated to the more explicit form. This can be implemented as a relatively trivial pre-parser pass and does not require modification of the parser itself. Indentation-sensitive syntax is introduced with a colon. Here are some simple examples showing how indentation-sensitive code is translated to prefix code which is then translated to "normal" code: a b c: d e f => a b (c d e f) => a b d e f c a b c: d e f: => a b (c d e (f g h)) => a b d e g h f c g h Finally, here again is our map example, this time even spiffier: f map = unlist: [] [x xs -> cons: (f x) (map xs f)] This looks quite close to the Haskell version, except that our programs are, after translation, still expressed only in terms of the functional forms of composition and quotation! (I was wrong in an earlier email when I started that composition is the only functional form in Joy. Quotation is also a functional form.) This definition is arguably easier to read than the postfix, pointfree alternative, as it clearly announces at the start that 'map' is a function that destructures a list, details the result of the destructization at the start of the relevant line, and indicates directly after that the result of the function will be a list via the prefixing of 'cons'. - John |
|
|
Re: sweetening concatenative syntaxMinor issues with the previous email:
1. I fell back to a Cat-like syntax for type definitions. Here are the correct notations for 'i', 'map', and 'unlist': i :: A [A -> B] -> B map :: (List a) [a -> b] -> (List b) unlist :: A (List b) [A -> C] [A b (List b) -> C] -> C Arguably there should be a type abbreviation for '(List a)'; perhaps '{a}'. 2. The phrase "allows editors to automatically intent" should read "allows editors to automatically INDENT". 3. By "it's harder for machines to generate valid code", I mean that it is harder to generate *source* code when compiling to a language with indentation-sensitive syntax. Explicit paired delimiters are easier to deal with. 4. It's too long. Unfortunately, I don't have the time to write a shorter version. |
|
|
Re: sweetening concatenative syntax> I. Lambda Expressions
> II. Local Function Variables Sure, these two seem reasonable seems reasonable. Factor and Cat support these. The only thing I have to say is, they shouldn't be used too often or for everything, since they can make code unnecessarily more verbose and less factorable. > III. Prefix Notation > Prefix notation may seem like a curiosity at first, perhaps existing > only to lure over those familiar with prefix notation. However, I'd > argue that prefix notation makes certain code objectively easier to > read. This is especially the case when dealing with deconstructors > like 'if' or 'unlist' as the higher order function of primary interest > is "announced" earlier in the definition. In the following example, > both functions are equivalent: > > f map = [] [x xs -> x f i xs f map cons] unlist > > f map = > (unlist [] > [x xs -> x f i xs f map cons]) > > (Perhaps this is not the best example. Substitute a better one with > nested ifs.) > > Prefix notation also has the benefit that you can express "nested" > code (as above) in a way that allows editors to automatically intent > properly. This is not at all the case with purely postfix code where > type information and perhaps some heuristics would need to be involved > to produce acceptable indentation. > > Here's a rewriting of map using *only* prefix notation in a way that > most any Scheme or Haskell programmer would find comfortable: > > f map = > (unlist [] > [x xs -> (cons (f x) (map xs f))]) > Sure, when you're just learning concatenative languages, it can be a little weird that "if" comes after the quotations, but humans don't read completely linearly in normal circumstances, and it doesn't take too much effort to look to the end. In a case where you have to look a page ahead, I'd say the fault lies with the author of the code writing things unreadably, rather than the language being unreadable. Also, what happens if a function is given too many arguments? The result is very counterintuitive, and a more useful translation would take into account type information. > IV. Indentation > > f map = unlist: > [] > [x xs -> cons: (f x) (map xs f)] I don't completely get it. This example doesn't take advantage of indentation, it only uses modified prefix syntax. I guess the indentation can make a difference if you have multiple arguments following the word, and then something else after that that's not an argument? Sure, there are lots of translations that we could make efficiently and accurately with concatenative languages, but I'm not sure if all of these are essential or beneficial to the nature of the languages. They make things more complicated and they remove all of the nice properties of concatenativity, which is useful in building software because it helps you factor code. We could easily create a translation from Scheme to a concatenative language, but that doesn't mean that we'd want to do all of our concatenative programming on a Scheme skin. |
|
|
Re: sweetening concatenative syntaxOn Mar 5, 2008, at 9:14 AM, Daniel Ehrenberg wrote: > Sure, there are lots of translations that we could make efficiently > and accurately with concatenative languages, but I'm not sure if all > of these are essential or beneficial to the nature of the languages. > They make things more complicated and they remove all of the nice > properties of concatenativity, which is useful in building software > because it helps you factor code. I'm not convinced concatenativity offers a huge advantage in factoring. It's easy to write code in such a way that useful chunks can't be pulled out. It's also difficult to find useful abstractions unless you have some experience. For example, I'd guess the novice programmer looking to add two lists together wouldn't accidently write zip-with. I think how factorable a language is primarily depends on its usefulness in building abstractions rather than any particular syntax. Languages with first class functions offer factorability that language like Forth don't offer. Haskell's type classes over a level of safe and structured factorability that's inaccessible to Joy. ML's functors offer a means of factoring I often miss when using Haskell. Types offer a way of verifying my abstractions in a way I miss when using Scheme. Scheme offers macros as a means of factoring that I miss when using Haskell. Et cetera. If a syntax that is non-concatenative makes it any easier to use any of the other means of factoring, then it seems to me it's worth considering. - John |
|
|
Re: sweetening concatenative syntaxOn Mar 5, 2008, at 3:14 PM, John Nowak wrote:
> I think how factorable a language is primarily depends on its > usefulness in building abstractions rather than any particular syntax. > Languages with first class functions offer factorability that language > like Forth don't offer. Haskell's type classes over a level of safe > and structured factorability that's inaccessible to Joy. ML's functors > offer a means of factoring I often miss when using Haskell. Types > offer a way of verifying my abstractions in a way I miss when using > Scheme. Scheme offers macros as a means of factoring that I miss when > using Haskell. Et cetera. I forgot an obvious one: Joy's stack-based nature, which makes it possible to return multiple values from a function and then easily consume them in another, opens up many possibilities for factoring that I often miss when using other languages. - John |
|
|
Re: sweetening concatenative syntax----- Original Message ----- From: "John Nowak" <john@...> To: <concatenative@...> Sent: Wednesday, March 05, 2008 3:39 PM Subject: Re: [stack] sweetening concatenative syntax > On Mar 5, 2008, at 3:14 PM, John Nowak wrote: > >> I think how factorable a language is primarily depends on its >> usefulness in building abstractions rather than any particular syntax. >> Languages with first class functions offer factorability that language >> like Forth don't offer. Haskell's type classes over a level of safe >> and structured factorability that's inaccessible to Joy. ML's functors >> offer a means of factoring I often miss when using Haskell. Types >> offer a way of verifying my abstractions in a way I miss when using >> Scheme. Scheme offers macros as a means of factoring that I miss when >> using Haskell. Et cetera. temperament, taste, and further imponderable subjectivities. perhaps a useful distinction to make is between monoglot and polyglot programmers. i'm an extreme case of the former, and you sound like you belong way over on the other edge. given the decision to code in a concatenative language, i want my concatenativity neat, straight no chaser. the sharp, clear outlines of the basic syntax are no small part of what i like about joy. in contrast to dan, i think introducing variables in any form should be resisted (although i've implemented both in my toy languages, just for the heck of it.) moreover, i agree with something dr. tanksley has often said: we don't yet know all the properties of these languages in their pure form, since no one (as far as i can tell from years on this list) has written any large-scale, multi-programmer, long-lived applications in any concatenative language. many small examples, much tinkering under the hood, but nothing approaching the scale of, say, ebay. > > I forgot an obvious one: Joy's stack-based nature, which makes it > possible to return multiple values from a function and then easily > consume them in another, opens up many possibilities for factoring > that I often miss when using other languages. > > - John > |
|
|
|
|
|
Re: sweetening concatenative syntaxHi, John --
Where can we read about Fifth? Several years ago, someone announced a Fifth language, is yours a continuation of that effort, or was that you? -- don On Mar 5, 2008, at 19:04 , John Nowak wrote: > I've had some thoughts recently on syntactic additions to > concatenative languages that seem potentially quite useful. At the > very least, they would put an end to silly discussions over largely > imagined deficiencies of postfix syntax and pointfree programming. > This is perhaps crucial if we expect any significant uptake of > concatenative languages. > > Below are the four extensions that I'm proposing. I'm strongly > considering one or more in the language I'm currently working on > (named "Fifth" for what are likely obvious reasons). The first two > should be fairly uncontroversial. The latter two are simple > translations I've not seen discussed before that seem potentially very > useful in practice. > > I. Lambda Expressions > > Assuming functions have the syntax '[<body>]', it seems useful to > introduce the syntax '[<bindings> -> <body>], where bindings are > ordered with the top of the stack towards the right as is familiar. > For example, the following two functions are equivalent: > > foo :: -> [a b -> b a a] > foo = [swap dup] > foo = [a b -> b a a] > > Note that the type syntax mimics the lambda expression syntax (or vice > versa if you prefer). The type notation is similar to Cat's with minor > alterations for the purposes of brevity. In particular, scalar > variables are all lowercase, row variables are all uppercase, and > concrete types are title-case and of at least two characters (to avoid > confusion with row variables). > > Variables should, of course, be lexically scoped. A translation of > expressions with lambdas to efficient pointfree stack-based code is > not especially difficult. This is the case regardless of if the > language is linear (which introduces only small complications), typed, > or "lacking" a retain stack. Of course, I elide the translation here > for the sake of... space. > > II. Local Function Variables > > If you permit lambdas, it makes sense to offer a simple syntax for > declaring functions with named variables. This is similar to how > Scheme offers '(define (foo <bindings>) <body>)' to mean '(define foo > (lambda (<bindings>) <body>))'. The declaration syntax proposed here > mimics use. In particular, the name of the function being defined > occurs *after* the arguments. > > The following two statements are equivalent (where 'i' is the identity > combinator with the type 'A (A -> B) -> B'): > > a b foo = b a a > foo = [a b -> b a a] i > > Here's another example in which 'unlist' is a deconstructor for a > list; the first function provided handled the null case and the second > handles the cons case: > > unlist :: A [b] (A -> C) (A b [b] -> C) -> C > > map :: [a] (a -> b) -> [b] > list f map = list [] [x xs -> x f i xs f map cons] unlist > > It should be noted that both lambda expressions and functions declared > with the local variable syntax may use more items on the stack than > they explicitly bind. For example, the following definition of map is > equivalent to the above and likely preferable in practice: > > f map = [] [x xs -> x f i xs f map cons] unlist > > III. Prefix Notation > > It occurred to me recently that there exists a simple syntactic > translation from prefix code (a la Scheme), where '(foo a b c)' is the > application of 'foo' to three arguments, to postfix code. This > translation can be done without any type information. The translation > consists of simply removing the parenthesis and placing the first > element at the end. If that first element is a local binding or a > lambda expression, an 'i' is prepended to cause it to be evaluated. > Here are some simple translation examples: > > (cons 1 null) => 1 null cons > (+ (- 1 2) 3) => 1 2 - 3 + > [f -> (f 10)] => [f -> 10 f i] > f foo = (f 5) => f foo = 5 f i > > Interestingly, you get partial application for free: > > double = (* 2) > > One thing that may seem like a problem is that '(1 2 3)' will be > translated to '(2 3 1)' when really an error should occur as '1' is > not a function. However, that's not the case: '1' *is* a function. > More precisely, it is a row polymorphic function that consumes a stack > and yields a new stack (1 :: A -> A int). As such, the above syntactic > translation is completely valid and it would be wrong to reject it. > > Prefix notation may seem like a curiosity at first, perhaps existing > only to lure over those familiar with prefix notation. However, I'd > argue that prefix notation makes certain code objectively easier to > read. This is especially the case when dealing with deconstructors > like 'if' or 'unlist' as the higher order function of primary interest > is "announced" earlier in the definition. In the following example, > both functions are equivalent: > > f map = [] [x xs -> x f i xs f map cons] unlist > > f map = > (unlist [] > [x xs -> x f i xs f map cons]) > > (Perhaps this is not the best example. Substitute a better one with > nested ifs.) > > Prefix notation also has the benefit that you can express "nested" > code (as above) in a way that allows editors to automatically intent > properly. This is not at all the case with purely postfix code where > type information and perhaps some heuristics would need to be involved > to produce acceptable indentation. > > Here's a rewriting of map using *only* prefix notation in a way that > most any Scheme or Haskell programmer would find comfortable: > > f map = > (unlist [] > [x xs -> (cons (f x) (map xs f))]) > > IV. Indentation > > Prefix notation is often criticized for being overly verbose or noisy. > The Python solution is to use indentation instead of paired > delimiters, but this introduces a number of problems: It's harder for > machines to generate valid code, pasting between sources can be messy, > editors can't really automatically re-indent code, plenty of people > (myself included) hate it, etc. > > The correct way to address this problem (if you are to address it at > all) is to do what Haskell does and offer *optional* indentation- > sensitive syntax that gets translated to the more explicit form. This > can be implemented as a relatively trivial pre-parser pass and does > not require modification of the parser itself. > > Indentation-sensitive syntax is introduced with a colon. Here are some > simple examples showing how indentation-sensitive code is translated > to prefix code which is then translated to "normal" code: > > a b c: d e f => a b (c d e f) => a b d e f c > > a b c: > d e f: => a b (c d e (f g h)) => a b d e g h f c > g h > > Finally, here again is our map example, this time even spiffier: > > f map = unlist: > [] > [x xs -> cons: (f x) (map xs f)] > > This looks quite close to the Haskell version, except that our > programs are, after translation, still expressed only in terms of the > functional forms of composition and quotation! (I was wrong in an > earlier email when I started that composition is the only functional > form in Joy. Quotation is also a functional form.) This definition is > arguably easier to read than the postfix, pointfree alternative, as it > clearly announces at the start that 'map' is a function that > destructures a list, details the result of the destructization at the > start of the relevant line, and indicates directly after that the > result of the function will be a list via the prefixing of 'cons'. > > - John > > > > Yahoo! Groups Links > > > > |
|
|
Re: sweetening concatenative syntaxOn Mar 5, 2008, at 5:26 PM, Stevan Apter wrote:
> temperament, taste, and further imponderable subjectivities. Well, perhaps this is worth testing then. Here's how I'm suggesting one could write a non-tail-recursive 'map' in terms of 'cons' and 'unlist': f map = unlist: [] [x xs -> (f x) (map xs f) cons] > i want my concatenativity neat, straight no chaser. How would you personally write this in a purely concatenative form? No cheating by using combinators like 'fold'; you only get to use 'cons' (a {a} -> {a}) and 'unlist' (A {b} [A -> C] [A b {b} -> C] -> C). - John |
|
|
Re: sweetening concatenative syntax----- Original Message ----- From: <john@...> To: <concatenative@...> Sent: Wednesday, March 05, 2008 9:03 PM Subject: Re: [stack] sweetening concatenative syntax > On Mar 5, 2008, at 5:26 PM, Stevan Apter wrote: > >> temperament, taste, and further imponderable subjectivities. > > Well, perhaps this is worth testing then. Here's how I'm suggesting one > could write a non-tail-recursive 'map' in terms of 'cons' and 'unlist': > > f map = unlist: > [] > [x xs -> (f x) (map xs f) cons] > >> i want my concatenativity neat, straight no chaser. > > How would you personally write this in a purely concatenative form? No > cheating by using combinators like 'fold'; you only get to use 'cons' (a > {a} -> {a}) and 'unlist' (A {b} [A -> C] [A b {b} -> C] -> C). my joy is so rusty these days. i'm on the wagon. in the g variant of my f language: [[dup!count![]top!]dip!swap! [[uncons!]dip!dup!top! [cons!unit!. first!swons!]dipd!] do!pop!pop!|] map "[..][f]map!" and in XY: ; map [jump] [each* rot => map <= swons] [pop] ifte ; ; each* => uncons <= tuck 2slip ; in both languages, all words are bottom out in symbolic primitives. six or seven for XY, rather more for g. details here: www.nsl.com. > > - John > > |
|
|
Re: sweetening concatenative syntaxOn Mar 5, 2008, at 8:34 PM, Don Groves wrote: > Where can we read about Fifth? At 5th.org, in a few weeks from now. > Several years ago, someone > announced a Fifth language, is yours a continuation of that effort, > or was that you? No, it wasn't me, nor is this a continuation of anything. - John |
|
|
Re: sweetening concatenative syntaxOn Mar 5, 2008, at 19:52 , John Nowak wrote:
> > On Mar 5, 2008, at 8:34 PM, Don Groves wrote: > >> Where can we read about Fifth? > > At 5th.org, in a few weeks from now. Thanks! > >> Several years ago, someone >> announced a Fifth language, is yours a continuation of that effort, >> or was that you? > > No, it wasn't me, nor is this a continuation of anything. I just figured that out. My references to Fifth are 20 years old ;-) -- don > > - John > > > > Yahoo! Groups Links > > > > |
|
|
Re: sweetening concatenative syntaxOn Mar 5, 2008, at 9:34 PM, Stevan Apter wrote:
> ; map [jump] [each* rot => map <= swons] [pop] ifte ; > ; each* => uncons <= tuck 2slip ; So that, versus this: f map = unlist: [] [x xs -> (f x) (map xs f) cons] It seems to me that the second version is objectively easier to understand. It's clear that 'map' destructures a list and it's clear how both possibilities (the null list and the non-null list) are handled. Even if we drop the prefix/indent syntax, it's still a good deal clearer: f map = [] [x xs -> x f i xs f map cons] unlist Actually, I like that better. At the very least, it seems that there's a strong argument for offering lambda expressions and a locals syntax. It's less clear that the prefix syntax is worthwhile. In particular, point Dan made is valid: > Also, what happens if a function is given too many arguments? The > result is very counterintuitive, and a more useful translation would > take into account type information. I'd be strongly opposed to any translation that was not a purely syntactic preprocessing step as otherwise you truly are complicating the language. At the moment, my type system can't enforce that a given quotation isn't given "too many" arguments because this makes no sense; all functions operate on stacks. The type system can enforce that a given quotation will try to use no more than a given number of arguments when it is later evaluated, and this is critical for typing combinators like 'infra', but that isn't helpful here. It is therefore probably best to rule out prefix syntax. - John |
|
|
Re: sweetening concatenative syntaxJohn Nowak <john@...> wrote:
> Daniel Ehrenberg wrote: > > Sure, there are lots of translations that we could make efficiently > > and accurately with concatenative languages, but I'm not sure if all > > of these are essential or beneficial to the nature of the languages. > > They make things more complicated and they remove all of the nice > > properties of concatenativity, which is useful in building software > > because it helps you factor code. > I'm not convinced concatenativity offers a huge advantage in > factoring. Sure it does! The referential transparency alone is worth the price of admission -- the famous "extract method" refactoring (considered by many to be the first indication of "true" refactoring support in a tool) is merely a cut-and-paste in any editor. > It's easy to write code in such a way that useful chunks > can't be pulled out. It's also difficult to find useful abstractions > unless you have some experience. For example, I'd guess the novice > programmer looking to add two lists together wouldn't accidently write > zip-with. You're totally right, but you're talking about a different subject. The experienced programmer isn't going to implement zip-with either; the experienced programmer knows it's already implemented. The experienced programmer is going to implement something that hasn't been done before, and notice that there's some redundancy, and if the language allows, will factor it out. If the language makes it hard, he'll tolerate a lot more redundancy. An really good programmer will also notice *almost* redundancies -- places where the code would be the same if only things were a little bit different. _That_ is the point that leads to the creation of truly reusable tools like zip-with -- not a magic knowledge of what sort of things will be reusable, but rather a repeated creation of the same sort of thing, and progressive refinement of that thing until it can actually be used in all of those cases. A good library is rarely produced directly from pure theory. Usually it's produced by painstaking experiments -- although if it's not backed by a good clean conceptual model it's a bad library, and experience won't save it. > I think how factorable a language is primarily depends on its > usefulness in building abstractions rather than any particular syntax. > Languages with first class functions offer factorability that language > like Forth don't offer. 100% agree, by the way. The problem of factoring can be addressed in many dimensions. > If a syntax that is non-concatenative makes it any easier to use any > of the other means of factoring, then it seems to me it's worth > considering. At this point in our understanding of concatenative languages, this is a pure cop-out. Yes, we don't have a concatenative Haskell yet -- but give us time. > - John -Wm |
|
|
Re: sweetening concatenative syntaxStevan Apter <sa@...> wrote:
> given the decision to code in a concatenative > language, i want my concatenativity neat, straight no chaser. Heh. I'm the same way -- of course. That's a little bit of the language researcher speaking rather than the true polyglot programmer, though. Like the chemist that I was trained as, I'm always wondering what would happen if I made a slightly purer extract. Well, I guess I skip the step of blowing the resulting extract up in my face -- that's the fun part of chemistry. > like about joy. in contrast to dan, i think introducing variables in > any form should be resisted (although i've implemented both in my toy > languages, just for the heck of it.) Yup. > moreover, i agree with something dr. tanksley has often said: Thank you, but I'm just Mr. Tanksley so far. I'm just starting on a Master's degree, so perhaps you'll be able to address me as "dread lord tanksley" in a while. (Is that the correct form of address?) > we don't yet know all the properties of > these languages in their pure form, since no one (as far as i can tell > from years on this list) has written any large-scale, multi-programmer, > long-lived applications in any concatenative language. many small > examples, much tinkering under the hood, but nothing approaching the > scale of, say, ebay. I'm not so sure about that. Forth has been used in enormous applications; see http://www.forth.com/resources/appNotes/index.html (and that's just one Forth company). Postscript forms one of the largest systems ever built (just about every computer is able to hook up to just about every Postscript printer almost right out of the box); it's not an integrated or monolithic system like eBay, but it's phenomenally successful at what it's designed to do. -Wm |
|
|
Re: sweetening concatenative syntaxJohn Nowak <john@...> wrote:
> Stevan Apter |