ASPN ActiveState Programmer Network
ActiveState
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups


Recent Messages
List Archives
About the List
List Leaders
Subscription Options

View Subscriptions
Help

View by Topic
ActiveState
.NET Framework
Open Source
Perl
PHP
Python
Tcl
Web Services
XML & XSLT

View by Category
Database
General
SOAP
System Administration
Tools
User Interfaces
Web Programming
XML Programming


MyASPN >> Mail Archive >> language-dev
language-dev
Re: Iterator Syntax
by Pixel other posts by this author
May 8 2002 1:11PM messages near this date
Re: Iterator Syntax | Re: Iterator Syntax
Glen Starchman <glenstar2@[...].com>  writes:

>  On Tuesday 07 May 2002 02:47 am, Donal K. Fellows wrote:
>  >   "hello".each(x) {
>  >       print(x)
>  >   }
>  >
>  > Problem with this is probably that the first x looks like an argument
>  > to each(); I suppose it is, but not in quite the normal sense in that
>  > it is a sort-of output-argument.  If you have local function closures
>  > you should probably use those, especially if they are introspectable
>  > in the number of arguments[*].  OTOH, I don't know enough about the
>  > syntax of your language to know how well that'd work (Java does this
>  > sort of thing, except with classes not functions, and it produces code
>  > that doesn't win awards for extreme syntactic elegance.)  :^/
>  
>  Hm... originally, I had something that looked like this:
>  
>  iterator_function() (block_arg,...) { block_body}
>  
>  That turned out to be rather hard to debug, IMO.

I don't know if you have anonymous functions, but you may consider using real
anonymous functions instead of "blocks".

Usually programming languages have:

- blocks like { ... } which are not first class (you can't pass them to
functions), allowed only for builtin constructs

- anonymous functions (lambda) which are first class constructs, but usually
less sugared and harder to use.

Solutions in various languages:

- perl: blocks and anonymous functions are nearly the same, the "sub" can be
removed when the callee declares the type (and is the first parameter)
  ->  very concise, but no sugar for arguments (only the ugly @_)
  ->  no distinction between parameter-less and parameter blocks
  ->  blocks allow lazy evaluation of the block

  sample: map { $_[0] * 2 } (1, 2)
          mapn { $_[0] + $_[1] } [1, 2], [3, 4]
          
          sub my_or { my ($a, $b) = @_; $a || &$b }
          $v = my_or(1, sub { print "foo" ; 2 });

- python: blocks are reserved for builtins. "lambda" is used for
parameter-using blocks. No special sugar for having the block separated from
the arguments
  ->  parameter-less blocks can be achieved with lambda *but* lambda only allow
     expressions, not statements

  sample: map(lambda e: e * 2, [1, 2])
          map(lambda a,b: a+b, [1, 2], [3, 4])

          # lambda only allow expressions. "print" being a statement, this
          # can't be done

          # with a special print_then:
          def print_then(s, v): print s ; return v
          def my_or(a, b): return a or b()
          v = my_or(1, lambda: print_then("foo", 2))

- ruby: blocks are a special beast allowing arguments, and are first class.
There is a distinction between functions and parameter blocks. Anonymous
functions are emulated with blocks. You can't have default-value (?) on
blocks, blocks must use "block.call(args)" instead of "func(args)". 

  sample: [1, 2].map{|e| e * 2}
          mapn([1, 2], [3, 4]){|a,b| a+b}

          def my_or(a) a || yield end
          v = my_or(1){ print "foo" ; 2 }

          def my_or(a,b) a || b.call end
          v = my_or(1, proc{print "foo" ; 2})


- haskell: due to lazy evaluation, parameter-less blocks are not evaluated, so
no special sugar is needed for them. All is simple :)
Also note that the sugar for anonymous functions is quite terse.

  sample: map (\e ->  e * 2) [1, 2]  or  map (* 2) [1, 2]
          zipWith (+) [1, 2] [3, 4]       

          my_or a b = if a then 1 else b
          v = my_or True (trace "foo" 2)

- ocaml: parameter-less blocks must be packed in an anonymous function.

  sample: map (fun e ->  e * 2) [ 1 ; 2 ]  or  map (( * ) 2) [ 1 ; 2 ]
          map2 (+) [ 1 ; 2 ] [ 3 ; 4 ]

          let my_or a b = if a then 1 else b()
          let v = my_or true (fun () ->  print_string "foo" ; 2)

- merd [*]: parameter-less blocks can be achieved with the magic Lazy in
arguments. The result is alike haskell

  sample: (1, 2).map(e ->  e * 2)  or  (1, 2).map(* 2)
          ((1, 2), (3, 4)).map2(+)

          my_or(a, Lazy(b)) = a ||| b
          v = my_or(1, ("foo".print ; 2))


- for more syntax for anonymous functions, look "anonymous functions" in
  http://merd.net/pixel/language-study/syntax-across-languages.html

[...]

>  But the iteration over multiple values would be a big tougher to intergate, 
>  although I did look at a top-level iterator function:
>  
>  iterate(a,b,c,d).each() { block}
>  
>  that would call the each method of each object in the chain. However, I 
>  couldn't think of a good use of that to save my life, so removed it.

well, this is used quite a lot in functional programming languages. If you
want to allow functional programming style... :)


[*] http://merd.net, my programming language
Thread:
Glen Starchman
Donal K. Fellows
Glen Starchman
Pixel
Glen Starchman
Buggs
Mathieu Bouchard
Buggs
Mathieu Bouchard
Glen Starchman

Privacy Policy | Email Opt-out | Feedback | Syndication
© ActiveState Software Inc. All rights reserved