|
View:
New views
5 Messages
—
Rating Filter:
Alert me
|
|
|
Joy and code readabilityHello everyone,
This is my first post here, so I thought I'd introduce myself a little bit: I'm a Ruby programmer (I program for fun, not for profit), and I recently became interested of the Joy language, especially of its minimalism. I also developed a small Ruby DSL <http://www.h3rald.com/concatenative> which implements some of Joy's combinators, just to see what's it like to work with a concatenative language <http://www.h3rald.com/articles/concatenative-programming-in-ruby> . After playing around a little bit, I just wanted to ask you guys how you cope with the (generally speaking) lack of readability of concatenative (but I'm referring mainly to Joy here) code. Although I really like everything concatenative programming offers, I'm somehow overwhelmened by it, in the sense that I find it more difficult to read (and mentally execute) concatenative code without local variables. How do you cope with that? Example (the famous quicksort in Joy): [small] [] [uncons [>] split] [[swap] dip cons concat] binrec To improve readability, the only thing I can think of is labeling each quoted program, using definitions, so: DEFINE remove_pivot_and_split_list == uncons [>] split insert_pivot_and_merge_lists == [swap] dip cons concat So we have: [small] [] [remove_pivot_and_split_list] [insert_pivot_and_merge_lists] binrec Definitely more descriptive and closer to a black box: each name identifies, roughly, how many items the program pops from the stack at the start and how many items pushes back at the end. Is there anything better than this? How do you keep track of what's going on the stack in a language with no variable assignments? Thanks, Fabio [Non-text portions of this message have been removed] |
|
|
Re: Joy and code readabilityfabio_cevasco scripsit:
> Although I really like everything concatenative programming offers, I'm > somehow overwhelmened by it, in the sense that I find it more difficult > to read (and mentally execute) concatenative code without local > variables. You've identified two of the three techniques: write very short words, and put a comment on each word saying what it does. The comment doesn't actually have to be the name, however. The third technique is to use stack comments, in the style of the Joy manual, showing what's expected on the stack and what winds up on the stack, with names chosen where possible to show the expected types. In some concatenative languages, the compiler actually verifies these comments, but not in Joy. -- John Cowan http://ccil.org/~cowan cowan@... Economists were put on this planet to make astrologers look good. --Leo McGarry |
|
|
Re: Joy and code readabilityfabio_cevasco wrote:
> After playing around a little bit, I just wanted to ask you guys how you > cope with the (generally speaking) lack of readability of concatenative > (but I'm referring mainly to Joy here) code. Reading -- and writing -- concatenative code is _different_. You have to learn some new thought patterns, and it'll take some time. > Although I really like everything concatenative programming offers, I'm > somehow overwhelmened by it, in the sense that I find it more difficult > to read (and mentally execute) concatenative code without local > variables. > How do you cope with that? You're on the right path; good naming is important. Forth programmers are urged to keep a thesaurus handy; terse, appropriate names for words are very useful to improve readability (long-winded names are better than a lack of factoring, but there are advantages to terseness as well). Being very willing to factor common sequences out into a word of their own also tends to be very helpful, so long as the result doesn't hide your intended algorithm. One of the biggest things, I think, is realizing that first, concatenative languages express algorithms, NOT expressions. Most languages are decent at expressing both sequences of actions (AKA processes, procedures, or algorithms) and expressions (AKA math formulas). Concatenative languages are specialized to express sequences of actions. > To improve readability, the only thing I can think of is labeling each > quoted program, using definitions, so: > DEFINE > remove_pivot_and_split_list == uncons [>] split > insert_pivot_and_merge_lists == [swap] dip cons concat Great! Get bolder and make two definitions for each of those: "remove_pivot", "split_list", "insert_pivot", and "merge_lists". > Is there anything better than this? How do you keep track of what's > going on the stack in a language with no variable assignments? Well, we do have a few rules. Nothing hard and fast, but most of them should make sense. Don't assume that one of the rules is more important than another one -- apply them to your situation. The first rule is to keep it simple. Try to write words that use three or fewer parameters, that take the parameters in a natural order (so you don't have to shuffle), that are short. A single line is ideal; three lines is excellent; eight lines is long. The second rule is to keep it algorithmic. An algorithm is "a finite set of unambiguous instructions performed in sequence to achieve a goal" (dictionary.com). Breaking this down, we see some sub-rules: * Keep your goal in mind and make it evident (probably in comments). * Keep your steps in mind and make them evident (probably in word names). * Keep your steps unambiguous (in choice of word names). * Show the sequence of steps clearly (probably by making one specific word contain ONLY the words that each implement each step in your algorithm). The third rule is to try to keep your stack effects clear; the programmer should be able to know what your code does without having to execute it in his head. It's possible to write code that consumes a variable number of items off the stack, but it's usually a bad idea. It's possible to write code that depends on knowing how deep the stack is... But likewise, usually a bad idea. It's easy to write code that does a lot of stack juggling, but modern concatenative languages provide combinators like cleave and spread that allow you to express your intentions in terms of how the data flows rather than how you want the stack to be juggled right now. The rest of the rules you'll find in any guide to good design -- you should seek highly coherent design, low coupling, clear purpose... These are just the ones that apply especially strongly to concatenative languages. (Yes, most languages work better with good algorithm expression, but it's an especially strong requirement with concatenative ones; and I think concatenative languages have some strength on the topic, since they are read in strict sequence left-to-right.) > Fabio -Wm |
|
|
Re: Joy and code readabilityCould you elaborate a bit more on stack comments? You mean writing (in Joy) something like:
(* A -> A A *) To say that the function (dup) consumes one item and puts two on the stack? Which concatenative languages verify these comments? Do they expect comments after the code they refer to, e.g. something similar to: [small] [] [uncons [>] split] (* [A B C] -> B [A] [C] *) [[swap] dip cons concat] (* A [B] [C] -> [B A C] *) binrec Thanks a lot! |
|
|
Re: Re: Joy and code readabilityOn Apr 1, 2009, at 5:25 AM, fabio_cevasco wrote: > Could you elaborate a bit more on stack comments? You mean writing > (in Joy) something like: > > (* A -> A A *) Yep. > Which concatenative languages verify these comments? Factor does. Cat may allow them; it's been awhile since I've looked at it. Cat will, however, automatically infer the effect in question for you. > Do they expect comments after the code they refer to, e.g. something > similar to: I believe it is only allowed for definitions as such: : over ( a b -- a b a ) [ dup ] dip swap ; - John |
| Free embeddable forum powered by Nabble | Forum Help |