shootout: implementing an interpreter for a simple procedural language Minim

  • Follow


\Jon suggested that it would be good to implement some significant
programs in different functional languages for comparison.  He
suggested interpreters for procedural languages like Basic.

QUOTE
There seems to be a great deal of interest from the functional
programming community in benchmarking. ..... I would also like to see
regexps, program evaluators (rewriters, interpreters and compilers)
and other benchmarks
UNQUOTE

Ok; here's a response - let's see if people want to try.

***********************************************************
The task is to implement an interpreter for a language Minim and run a
stock Minim program that adds two numbers x and y together where x =
100000 (10^5) and y = 100000 (10^5) and give the times.
***********************************************************

Minim is a very basic language - fairly close to assembly. Minim can

1. assign number constants to variables
2. assign the value of a variable to a variable
3. decrement or increment a variable
4. compare two values (numbers or variables) by >, < or =.
5. perform if then else tests
6. jump to a tag
7. print a string
8. print a value (i.e. a number or the value of a variable)
9. input a number value from a user into a variable
10. print a new line
11. do AND, NOT and OR boolean tests

Here's Minim Syntax in BNF with comments

<program> := <statement>
             | <statement> <program>;
<statement> := <assignment>
                | <conditional>
                | <goto>
                | <tag>;
                | <print>
                | <input>
<assignment> := (<var> is <val>)     { assign a value to a variable }
                | (++ <var>)         { increment a variable }
                | (-- <var>);        { decrement a variable }
<val> := <constant> | <var>;
<var> := any symbol;
<constant> := any number
<conditional> := (if <test> then <statement> else <statement>);
<test> := (<val> <comp> <val>)
          | (<test> and <test>);     { boolean AND}
          | (<test> or <test>)       {boolean OR}
          | (not <test>);            {boolean NOT}
<comp> := > | < | =;
<goto> := (goto <tag>);              {go to}
<tag> := any symbol
<print> := (print <string>) | (print <val>); nl;  {nl is new line}
<input> := (input <var>);               {input the users response to
var}
<string> := any string;

Here's the stock program to add two numbers together in Minim -
designed to here run under Qi. You should be able to follow it.

[      [print "Add x and y"]
       nl
       [print "Input x: "]
       [input x]
       nl
       [print "Input y: "]
       [input y]
       main
       [if [x = 0] then [goto end] else [goto sub1x]]

       sub1x
       [-- x]
       [++ y]
       [goto main]

       end
       nl
       [print "The total of x and y is "]
       [print y]
       nl]

A Qi Solution
_____________

Here's a type secure implementation of an interpreter for Minim in Qi.
The type theory encapsulates the BNF and is 54 lines of sequent
calculus.\

(synonyms program [statement]
          env [(symbol * number)])

(datatype statement

   Var : symbol; Val : val;
   =========================
   [Var is Val] : statement;

   if (element? Op [++ --])
   Var : symbol;
   =====================
   [Op Var] : statement;

   Test : test; DoThis : statement; DoThat : statement;
   ====================================================
   [if Test then DoThis else DoThat] : statement;

   Tag : symbol;
   ======================
   [goto Tag] : statement;

   Message : string-or-val;
   ============================
   [print Message] : statement;

   Message : string;
   _________________
   Message : string-or-val;

   Message : val;
   _________________
   Message : string-or-val;

   Var : symbol;
   =========================
   [input Var] : statement;

   Tag : symbol;
   _____________
   Tag : statement;)

(datatype test

   if (element? Comp [= > <])
   Val1 : val; Val2: val;
   ======================
   [Val1 Comp Val2] : test;

   if (element? LogOp [and or])
   Test1 : test;
   Test2 : test;
   =============
   [Test1 LogOp Test2] : test;

   Test : test;
   ==================
   [not Test] : test;)

(datatype val

   ______________________________________
   (number? N) : verified >> N : number;

   _______________________________________
   (symbol? S) : verified >> S : symbol;

   Val : symbol;
   _______________
   Val : val;

   Val : number;
   _____________
   Val : val;)

\The program that runs Minim programs is 56 lines of Qi and is given
here.\

(define run
   {program --> env}
    Program -> (run-loop Program Program []))

(define run-loop
   {program --> program --> env --> env}
    [] _ Env -> Env
    [nl | Ss] Program Env -> (do (output "~%") (run-loop Ss Program
Env))
    [Tag | Ss] Program Env -> (run-loop Ss Program Env)	where (symbol?
Tag)
    [[goto Tag] | _] Program Env -> (run-loop (go Tag Program) Program
Env)
    [[Var is Val] | Ss] Program Env
    -> (run-loop Ss Program (change-env Var (compute-val Val Env)
Env))
    [[++ Var] | Ss] Program Env
    -> (run-loop Ss Program (change-env Var (+ 1 (look-up Var Env))
Env))
    [[-- Var] | Ss] Program Env
    -> (run-loop Ss Program (change-env Var (- (look-up Var Env) 1)
Env))
    [[if Test then DoThis else DoThat] | Ss] Program Env
     -> (if (perform-test? Test Env)
            (run-loop [DoThis | Ss] Program Env)
            (run-loop [DoThat | Ss] Program Env))
    [[print M] | Ss] Program Env -> (do (output "~A" (look-up M Env))
                                        (run-loop Ss Program Env))
										where (symbol? M)
    [[print M] | Ss] Program Env -> (do (output "~A" M)
                                        (run-loop Ss Program Env))
    [[input Var] | Ss] Program Env
       -> (run-loop Ss Program (change-env Var (input+ : number)
Env)))

(define compute-val
  {val --> env --> number}
   N _ -> N	where (number? N)
   Var Env -> (look-up Var Env)	where (symbol? Var))

(define go
  {symbol --> program --> program}
   Tag [Tag | Program] -> Program
   Tag [_ | Program] -> (go Tag Program)
   Tag _ -> (error "cannot go to tag ~A~%" Tag))

(define perform-test?
  {test --> env --> boolean}
   [Test1 and Test2] Env -> (and (perform-test? Test1 Env)
                                 (perform-test? Test2 Env))
   [Test1 or Test2] Env -> (or (perform-test? Test1 Env)
                               (perform-test? Test2 Env))
   [not Test] Env -> (not (perform-test? Test Env))
   [V1 = V2] Env -> (= (compute-val V1 Env) (compute-val V2 Env))
   [V1 > V2] Env -> (> (compute-val V1 Env) (compute-val V2 Env))
   [V1 < V2] Env -> (< (compute-val V1 Env) (compute-val V2 Env)))

(define change-env
   {symbol --> number --> env --> env}
    Var Val [] -> [(@p Var Val)]
    Var Val [(@p Var _) | Env] -> [(@p Var Val) | Env]
    Var Val [Binding | Env] -> [Binding | (change-env Var Val Env)])

(define look-up
  {symbol --> env --> number}
   Var [] -> (error "~A is unbound.~%" Var)
   Var [(@p Var Val) | _] -> Val
   Var [_ | Env] -> (look-up Var Env))

\Here is a trial run -

NB: This is run under CLisp which is *much* slower than SBCL.  My
version of SBCL (1.0) for Windows is rather neurotic and I've had to
choose the slower but more stable CLisp.  This means I've probably
lost out by a factor of 4 (at a guess).

Qi 2007, Copyright (C) 2001-2007 Mark Tarver
www.lambdassociates.org
version 9.0 (Turbo-E)


(0-) (tc +)
true

(1+) (turbo +)
true : boolean

(2+) (load "minim.txt")
compiled : unit
statement : unit
test : unit
val : unit
run : ((list statement) --> (list (symbol * number)))
run-loop :
((list statement) -->
 ((list statement) -->
  ((list (symbol * number)) --> (list (symbol * number)))))
compute-val : (val --> ((list (symbol * number)) --> number))
go : (symbol --> ((list statement) --> (list statement)))
perform-test? : (test --> ((list (symbol * number)) --> boolean))
change-env :
(symbol -->
 (number --> ((list (symbol * number)) --> (list (symbol * number)))))
look-up : (symbol --> ((list (symbol * number)) --> number))
typechecked in 22217 inferences.

Real time: 0.875 sec.
Run time: 0.859375 sec.
Space: 11044772 Bytes
GC: 21, GC time: 0.140625 sec.
loaded : symbol

(3+) (time (run [
       [print "Add x and y"]
       nl
       [print "Input x: "]
       [input x]
       nl
       [print "Input y: "]
       [input y]
       main
       [if [x = 0] then [goto end] else [goto sub1x]]

       sub1x
       [-- x]
       [++ y]
       [goto main]

       end
       nl
       [print "The total of x and y is "]
       [print y]
       nl]))
Add x and y
Input x: 100000

Input y: 100000

The total of x and y is 200000

Real time: 12.15625 sec.
Run time: 2.125 sec.
Space: 7210116 Bytes
GC: 14, GC time: 0.03125 sec.
[(@p x 0) (@p y 200000)] : (list (symbol * number))

(4+)

This whole post is a commented Qi program so you can load it into Qi.

Mark \

0
Reply dr.mtarver (661) 7/18/2007 12:24:53 AM

Mark Tarver wrote:
> Minim is a very basic language - fairly close to assembly.

This is ok but I think minim is a little too simple.

> Here's the stock program to add two numbers together in Minim -
> designed to here run under Qi. You should be able to follow it.
> 
> [      [print "Add x and y"]
>        nl
>        [print "Input x: "]
>        [input x]
>        nl
>        [print "Input y: "]
>        [input y]
>        main
>        [if [x = 0] then [goto end] else [goto sub1x]]
> 
>        sub1x
>        [-- x]
>        [++ y]
>        [goto main]
> 
>        end
>        nl
>        [print "The total of x and y is "]
>        [print y]
>        nl]

Can you write a parser so the program can be loaded from a text file written
in the syntax you described? Unfair to hard code it...

Here's my expr.ml:

type 'var value =
  | Int of int
  | Var of 'var

type 'var test =
  | Less of 'var value * 'var value
  | Equal of 'var value * 'var value
  | Greater of 'var value * 'var value
  | And of 'var test * 'var test
  | Or of 'var test * 'var test
  | Not of 'var test

type ('var, 'tag) statement =
  | Assign of 'var * 'var value
  | Incr of 'var
  | Decr of 'var
  | If of 'var test * ('var, 'tag) statement * ('var, 'tag) statement
  | Goto of 'tag
  | Tag of 'tag
  | PrintString of string
  | Print of 'var
  | Input of 'var

type program = (string, string) statement list

> A Qi Solution
> _____________
> 
> Here's a type secure implementation of an interpreter for Minim in Qi.
> The type theory encapsulates the BNF and is 54 lines of sequent
> calculus.

Can you give an example of errors that your static type system catches?

Here's my lexer.mll:

{
open Parser
open Expr

let start = ref 1 and line = ref 1

let newline lexbuf =
  start := lexbuf.Lexing.lex_curr_p.Lexing.pos_cnum;
  incr line

let ident = function
  | "is" -> IS
  | "if" -> IF
  | "then" -> THEN
  | "else" -> ELSE
  | "goto" -> GOTO
  | "print" -> PRINT
  | "nl" -> NL
  | "input" -> INPUT
  | "and" -> AND
  | "or" -> OR
  | "not" -> NOT
  | s -> IDENT s
}

let digit = ['0'-'9']
let alpha = ['a'-'z' 'A'-'Z']+
let ident = alpha+ (alpha | digit)*

rule token = parse
  | '\n'            { newline lexbuf; token lexbuf }
  | [' ' '\t' '\r'] { token lexbuf }
  | '='             { EQUAL }
  | "++"            { INC }
  | "--"            { DEC }
  | '<'             { LESS }
  | '='             { EQUAL }
  | '>'             { GREATER }
  | digit+ as s     { INT (int_of_string s) }
  | ident as s      { ident s }
  | '"' (("\\\"" | [^ '"'])* as s) '"' { STRING s }
  | eof             { EOF }

Here's my parser.mly:

%{
  open Expr
%}

%token <string> STRING IDENT
%token <int> INT
%token IS IF THEN ELSE GOTO PRINT NL INPUT AND OR NOT EOF INC DEC LESS EQUAL
GREATER

%start program
%type <Expr.program> program

%%

program:
| statement program                       { $1 :: $2 }
| statement EOF                           { [$1] };

statement:
| IDENT IS value                          { Assign($1, $3) }
| INC IDENT                               { Incr $2 }
| DEC IDENT                               { Decr $2 }
| IF test THEN statement ELSE statement   { If($2, $4, $6) }
| GOTO IDENT                              { Goto $2 }
| IDENT                                   { Tag $1 }
| PRINT STRING                            { PrintString $2 }
| PRINT IDENT                             { Print $2 }
| NL                                      { PrintString "\n" }
| INPUT IDENT                             { Input $2 };

value:
| INT                                     { Int $1 }
| IDENT                                   { Var $1 };

test:
| value LESS value    { Less($1, $3) }
| value EQUAL value   { Equal($1, $3) }
| value GREATER value { Greater($1, $3) }
| test AND test       { And($1, $3) }
| test OR test        { Or($1, $3) }
| NOT test            { Not $2 };

> \The program that runs Minim programs is 56 lines of Qi and is given
> here.\

Here's my 43-line eval.ml:

open Expr
open Printf

module Bindings = Map.Make(String)

let set m x y = Bindings.add x y m

let get m x = Bindings.find x m

let tags_of program =
  let aux (pc, tags) = function
    | Tag t -> pc+1, Bindings.add t pc tags
    | _ -> pc+1, tags in
  let _, tags = Array.fold_left aux (0, Bindings.empty) program in
  tags

let eval vars = function
  | Int n -> n
  | Var v -> get vars v

let rec test vars = function
  | Less(f, g) -> eval vars f < eval vars g
  | Equal(f, g) -> eval vars f = eval vars g
  | Greater(f, g) -> eval vars f > eval vars g
  | And(f, g) -> test vars f && test vars g
  | Or(f, g) -> test vars f || test vars g
  | Not f -> not(test vars f)

let rec statement tags vars pc = function
  | Assign(x, y) -> set vars x (eval vars y), pc + 1
  | Incr x -> set vars x (get vars x + 1), pc + 1
  | Decr x -> set vars x (get vars x - 1), pc + 1
  | If(p, t, f) -> statement tags vars pc (if test vars p then t else f)
  | Goto tag -> vars, Bindings.find tag tags
  | Tag _ -> vars, pc + 1
  | PrintString s -> print_string s; vars, pc + 1
  | Print x -> print_int(get vars x); vars, pc + 1
  | Input x -> set vars x (int_of_string(input_line stdin)), pc + 1

let rec run program tags (vars, pc) =
  run program tags (statement tags vars pc program.(pc))

let () =
  match Sys.argv with
  | [|_; file|] ->
      let ch = open_in file in
      let program = Parser.program Lexer.token (Lexing.from_channel ch) in
      close_in ch;
      let program = Array.of_list program in
      (try run program (tags_of program) (Bindings.empty, 0) with _ -> ())
  | _ -> invalid_arg "Usage: ./minim <file>"

> NB: This is run under CLisp which is *much* slower than SBCL.  My
> version of SBCL (1.0) for Windows is rather neurotic and I've had to
> choose the slower but more stable CLisp.  This means I've probably
> lost out by a factor of 4 (at a guess).
> ...
> The total of x and y is 200000
> 
> Real time: 12.15625 sec.
> Run time: 2.125 sec.

I get roughly the same performance from OCaml's interpreted bytecode:

$ ocamlbuild eval.byte
+ /usr/bin/ocamlyacc parser.mly
6 shift/reduce conflicts.
Finished, 13 targets (0 cached) in 00:00:03.
$ time ./eval.byte test.minim <args.txt
Add x and y
Input x:
Input y:
The total of x and y is 200000

real    0m0.583s
user    0m0.569s
sys     0m0.005s

However, native-code is over an order of magnitude faster:

$ ocamlbuild eval.native
Finished, 16 targets (11 cached) in 00:00:03.
$ time ./eval.native test.minim <args.txt
Add x and y
Input x:
Input y:
The total of x and y is 200000

real    0m0.050s
user    0m0.048s
sys     0m0.001s

To optimize this, I would precompute branch targets and variable space,
substituting the gotos and variable references with integers instead of
strings. I deliberately parameterized the expr type over the types of
variables and tags to make this easy.

> This whole post is a commented Qi program so you can load it into Qi.

Now that is cool. :-)

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/18/2007 5:36:59 AM


Mark Tarver <dr.mtarver@ukonline.co.uk> writes:
> The task is to implement an interpreter for a language Minim and run a
> stock Minim program that adds two numbers x and y together where x =
> 100000 (10^5) and y = 100000 (10^5) and give the times.

This is too easy to game.  Think of the obvious Lisp approach of
translating the Minim program into an S-expression and evaluating it.
Now think of an evaluator that automatically invokes an optimizing
compiler and memoizes the resulting machine code.  You see where this
leads.
0
Reply phr.cx (5483) 7/18/2007 5:41:59 AM

Paul Rubin wrote:
> This is too easy to game.  Think of the obvious Lisp approach of
> translating the Minim program into an S-expression and evaluating it.
> Now think of an evaluator that automatically invokes an optimizing
> compiler and memoizes the resulting machine code.  You see where this
> leads.

I think that's exactly what makes this benchmark interesting.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/18/2007 5:48:50 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> > Now think of an evaluator that automatically invokes an optimizing
> > compiler and memoizes the resulting machine code.  You see where this
> > leads.
> 
> I think that's exactly what makes this benchmark interesting.

Are you kidding?  Think of Kyoto Common Lisp for example.  It compiles
Lisp functions into C code, invokes cc, and loads the resulting object
file.  The benchmark becomes a test of the external C compiler.
0
Reply phr.cx (5483) 7/18/2007 6:15:54 AM

Paul Rubin schrieb:
> Jon Harrop <jon@ffconsultancy.com> writes:
>>> Now think of an evaluator that automatically invokes an optimizing
>>> compiler and memoizes the resulting machine code.  You see where this
>>> leads.
>> I think that's exactly what makes this benchmark interesting.
> 
> Are you kidding?  Think of Kyoto Common Lisp for example.  It compiles
> Lisp functions into C code, invokes cc, and loads the resulting object
> file.  The benchmark becomes a test of the external C compiler.

Well, the external C compiler is a part of the compiler, then, so this 
is actually OK.

I agree with Jon that having a benchmark that tests the compiler's 
ability to pre-evaluate stuff isn't a bad idea.
I also agree with Paul that this benchmark tests a rather narrow 
spectrum of cases (and probably not the case that Mark had in mind).

I think the benchmark should be split into variants: one that evaluates 
a constant expression (tests compile-time evaluation), one that accepts 
parameters for a fixed Minim program (tests partial compile-time 
evaluation), and one that takes a Minim program as a parameter (tests 
symbolic evaluation).

Regards,
Jo
0
Reply jo427 (1164) 7/18/2007 6:33:26 AM

Paul Rubin wrote:
> Are you kidding?  Think of Kyoto Common Lisp for example.  It compiles
> Lisp functions into C code, invokes cc, and loads the resulting object
> file.  The benchmark becomes a test of the external C compiler.

Then that feature of Kyoto CL gives it an advantage over OCaml, which has no
built-in evaluator. That's something I'd like to measure. I'd also like to
compare with MetaOCaml's built-in evaluator that compiles using ocamlopt.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/18/2007 6:35:03 AM

Jon Harrop wrote:
> ...

I've added preprocessors that convert the string representations of variable
and tag names in the abstract syntax tree into int refs and int program
counters, respectively. The code that does this is really beautiful,
totalling only 26 more lines of code. The core new higher-order
function "subst" has the inferred type:

val subst :
  ('a -> 'b) ->
  ('c -> 'd) -> ('c, 'a) Expr.statement -> ('d, 'b) Expr.statement

Also, the program ran correctly the first time it passed type checking.

This makes the whole interpreter ~6x faster with the given benchmark now
taking only 0.008s:

open Expr
open Printf

let tags_of program =
  let aux (pc, tags) = function
    | Tag t -> pc, (t, pc)::tags
    | _ -> pc+1, tags in
  snd(List.fold_left aux (0, []) program)

let vars_of program =
  let aux (n, tags) = function
    | Assign(x, _) | Input x -> n+1, (x, ref 0)::tags
    | _ -> n+1, tags in
  snd(List.fold_left aux (0, []) program)

let subst_val vars = function
  | Int n -> Int n
  | Var x -> Var(vars x)

let rec subst_test vars = function
  | Less(x, y) -> Less(subst_val vars x, subst_val vars y)
  | Equal(x, y) -> Equal(subst_val vars x, subst_val vars y)
  | Greater(x, y) -> Greater(subst_val vars x, subst_val vars y)
  | And(x, y) -> And(subst_test vars x, subst_test vars y)
  | Or(x, y) -> Or(subst_test vars x, subst_test vars y)
  | Not x -> Not(subst_test vars x)

let rec subst tags vars = function
  | Assign(x, y) -> Assign(vars x, subst_val vars y)
  | Incr x -> Incr(vars x)
  | Decr x -> Decr(vars x)
  | If(p, t, f) -> If(subst_test vars p, subst tags vars t, subst tags vars
f)
  | Goto tag -> Goto(tags tag)
  | Tag _ -> invalid_arg "Unexpected tag"
  | PrintString s -> PrintString s
  | Print x -> Print(vars x)
  | Input x -> Input(vars x)

let not_tag = function Tag _ -> false | _ -> true

let eval = function
  | Int n -> n
  | Var v -> !v

let rec test = function
  | Less(f, g) -> eval f < eval g
  | Equal(f, g) -> eval f = eval g
  | Greater(f, g) -> eval f > eval g
  | And(f, g) -> test f && test g
  | Or(f, g) -> test f || test g
  | Not f -> not(test f)

let rec statement pc = function
  | Assign(x, y) -> x := eval y; pc + 1
  | Incr x -> incr x; pc + 1
  | Decr x -> decr x; pc + 1
  | If(p, t, f) -> statement pc (if test p then t else f)
  | Goto tag -> tag
  | Tag _ -> pc + 1
  | PrintString s -> print_string s; pc + 1
  | Print x -> print_int !x; pc + 1
  | Input x -> x := int_of_string(input_line stdin); pc + 1

let rec run program pc =
  run program (statement pc program.(pc))

let () =
  match Sys.argv with
  | [|_; file|] ->
      let ch = open_in file in
      let program = Parser.program Lexer.token (Lexing.from_channel ch) in
      close_in ch;
      let tags = (fun m k -> List.assoc k m) (tags_of program) in
      let vars = (fun m k -> List.assoc k m) (vars_of program) in
      let program = List.filter not_tag program in
      let program = List.map (subst tags vars) program in
      let program = Array.of_list program in
      (try run program 0 with _ -> ())
  | _ -> invalid_arg "Usage: ./minim <file>"

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/18/2007 6:44:36 AM

Paul Rubin wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> Then that feature of Kyoto CL gives it an advantage over OCaml,
>> which has no built-in evaluator. That's something I'd like to
>> measure. I'd also like to compare with MetaOCaml's built-in
>> evaluator that compiles using ocamlopt.
> 
> I wonder if it fits the shootout specification to just compile the
> Minim program into machine code and then either invoke it externally
> or load it into Ocaml through an FFI and run it.

Fine by me but the overhead of full-blown compilation will be significant.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/18/2007 6:46:22 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> Then that feature of Kyoto CL gives it an advantage over OCaml,
> which has no built-in evaluator. That's something I'd like to
> measure. I'd also like to compare with MetaOCaml's built-in
> evaluator that compiles using ocamlopt.

I wonder if it fits the shootout specification to just compile the
Minim program into machine code and then either invoke it externally
or load it into Ocaml through an FFI and run it.
0
Reply phr.cx (5483) 7/18/2007 6:50:54 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> Fine by me but the overhead of full-blown compilation will be significant.

Nah.  I mean invoking a heavyweight compiler like gcc would be slow,
but once you have a parse tree, you can spew straightforward machine
code that might be lousy by serious compiler standards, but should
still be much faster than any interpreter.  You can even do that
sort of portably:

  http://www.gnu.org/software/lightning/manual/lightning.html#Overview

There have also been Lisps that had embedded compilers and evalled by
generating machine code directly rather than invoking cc like KCL did.
Yale's T system (a Scheme dialect) did that.  I don't remember its
read-eval-print loop pausing noticably even on the comparatively slow
machines of the 1990's (I think I used it on a Sun 3).
0
Reply phr.cx (5483) 7/18/2007 7:37:53 AM

Paul Rubin wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> Fine by me but the overhead of full-blown compilation will be
>> significant.
> 
> Nah.  I mean invoking a heavyweight compiler like gcc would be slow,

Yes.

> but once you have a parse tree, you can spew straightforward machine
> code that might be lousy by serious compiler standards, but should
> still be much faster than any interpreter.

True. That could be a lot of work though.

> You can even do that sort of portably:
> 
>   http://www.gnu.org/software/lightning/manual/lightning.html#Overview

Doesn't support amd64, which rules it out for me.

> There have also been Lisps that had embedded compilers and evalled by
> generating machine code directly rather than invoking cc like KCL did.
> Yale's T system (a Scheme dialect) did that.  I don't remember its
> read-eval-print loop pausing noticably even on the comparatively slow
> machines of the 1990's (I think I used it on a Sun 3).

I was under the impression that most Lisp compilers did this. What does SBCL
do?

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/18/2007 7:49:09 AM

Jon Harrop <jon@ffconsultancy.com> writes:

> 
> > There have also been Lisps that had embedded compilers and evalled by
> > generating machine code directly rather than invoking cc like KCL did.
> > Yale's T system (a Scheme dialect) did that.  I don't remember its
> > read-eval-print loop pausing noticably even on the comparatively slow
> > machines of the 1990's (I think I used it on a Sun 3).
> 
> I was under the impression that most Lisp compilers did this. What does SBCL
> do?

Most of them do (SBCL doesn't even have an interpreter AFAIK). 

Andras
0
Reply asimon (154) 7/18/2007 10:09:59 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> >   http://www.gnu.org/software/lightning/manual/lightning.html#Overview
> Doesn't support amd64, which rules it out for me.

I thought that was added recently.

> > There have also been Lisps that had embedded compilers and evalled by
> > generating machine code directly rather than invoking cc like KCL did.
> 
> I was under the impression that most Lisp compilers did this. What does SBCL
> do?

I thought it was more conventional to have both a compiler and an
interpreter, but I haven't used many full-scale CL implementations.
0
Reply phr.cx (5483) 7/18/2007 4:39:41 PM

!!
This post is a commented PILS program.
It compiles the minix stock program to a set of PILS rules and executes
it by repeatingly applying the ruleset to a state node that holds the 
variables.

The style is what I call narrative programming - I start with
the mimix program in a text literal, then describe what to do with it.

Parsing is done with a cheat - using 9 code lines.
The compiler as such approx. 45 code lines. I tried to cover all minix.
The "minix runtime" is 30-odd lines, mostly because PILS doesn't have
a console interface - the text input/output is done via wxWidgets dialogs.

Execution time for 100000 + 100000 is approx. 1.7 seconds on a
2GHz dual core2, using the VC2005 release build of the PILS system.
(Actually, I tested with 1000000 + 1000000 and got 17 seconds.)
I made the compiler as simple as possible - a few simple optimisations
would make it somewhat faster.
!!

{.test
|:ok

!!
Here goes the minix stock program.
String delimiters are doubled, by PILS convention
!!

"
(print ""Add x and y (what a feat!)"")
nl
(print ""Input x: "")
(input x)
nl
(print ""Input y: "")
(input y)
main
(if (x = 0) then (goto end) else (goto sub1x))

sub1x
(-- x)
(++ y)
(goto main)

end
nl
(print ""The total of x and y is "")
(print y)
nl
"

!!
To parse it using the PILS constant syntax,
 replace () with [list: ] outside strings.
!!

  split """"
  split 2
  each
  ( { a, b |:ok process (a), b }
    { a, | :ok process (a) }
    where
    { process: string | :ok string replace ["(" "[list: " ")" "]"] } )
  splice splice """"

!!
enclose in [] and readt, using the PILS parser
!!

  call {s|:ok ?:? read ("[" (s) "]") }

!!
compile to tagged actions
!!

  listwise counting
  { number := statement
  | list [actions] :=
    ?tag number
    .action
    ?next (' ?state) head (tag: number + 1);
    statement try
    { / tag | :ok list [actions] := (?tag .action next); next }
    { .nl | :ok ::- ' print ""/; next }
    { list: [print], / v | :ok ::- (: print (: ' state . v)); next }
    { list: [print], $ string | :ok ::- (: print (string)); next }
    { list: [input], / v | :ok v := ' input }
    { list: [goto], / v | :ok ' (?state) head: tag: v }
    { list: [++], / v | :ok v := : val (v) + 1 }
    { list: [--], / v | :ok v := : val (v) - 1 }
    { list: / a, [is], b | :ok a := val (b) }
    { list: [if], if, [then], then, [else], else
    | :self :ok
      ::if . try
      { list: a, [=], b | :ok : val (a) = val (b) }
      { list: a, [<], b | :ok : val (a) < val (b) }
      { list: a, [>], b | :ok : val (a) > val (b) }
      { list: a, [and], b | :self :ok ::if a try (self); b try (self) }
      { list: a, [or], b | :self :ok ::if a try (self); 1 .else b try 
(self) }
      { list: [not], a | :self :ok : a <> 1 }
      ; then try (self)
      .else . try (self)
    }
    where
    ! This rule implements assignment by constructing a new state
    { / v := e
    | :where :ok
      next merge: ?state
      : (' state) merge: (node [?] (where . v) := e) node [?]
    }
    ! Constant vals are as-is, variables must be fetched from the state
    { .val (= e) | :ok e }
    { .val (/ v) | :ok : ' state . v }
  }
  list [actions]
  ! tag/action pairs are wrapped
  every
  {?tag .action
  | :ok ?match (' ?state) head (tag: tag) .action (::ok action)
  }

  first [?]
  fold {rules := ?match .action|:ok ::match .action ; rules}
  call {rules | :ok ::ruleset rules}

!!
This produces the following PILS rules:
{[tag: 1]: .state|:ok :- print "Add x and y (what a feat!)"; [tag: 2]: 
..state}
{[tag: 2]: .state|:ok :- print ""/; [tag: 3]: .state}
{[tag: 3]: .state|:ok :- print "Input x: "; [tag: 4]: .state}
{[tag: 4]: .state|:ok [tag: 5]: .state . merge (?x input)}
{[tag: 5]: .state|:ok :- print ""/; [tag: 6]: .state}
{[tag: 6]: .state|:ok :- print "Input y: "; [tag: 7]: .state}
{[tag: 7]: .state|:ok [tag: 8]: .state . merge (?y input)}
{[tag: main]: .state|:ok [tag: 9]: .state}
{[tag: 8]: .state|:ok [tag: 9]: .state}
{[tag: 9]: .state|:ok :else ([tag: sub1x]: .state) .if state v = 0; [tag: 
end]: .state}
{[tag: sub1x]: .state|:ok [tag: 11]: .state}
{[tag: 10]: .state|:ok [tag: 11]: .state}
{[tag: 11]: .state|:ok [tag: 12]: .state . merge (?x state v - 1)}
{[tag: 12]: .state|:ok [tag: 13]: .state . merge (?y state v + 1)}
{[tag: 13]: .state|:ok [tag: main]: .state}
{[tag: end]: .state|:ok [tag: 15]: .state}
{[tag: 14]: .state|:ok [tag: 15]: .state}
{[tag: 15]: .state|:ok :- print ""/; [tag: 16]: .state}
{[tag: 16]: .state|:ok :- print "The total of x and y is "; [tag: 17]: 
..state}
{[tag: 17]: .state|:ok :- print (state v); [tag: 18]: .state}
{[tag: 18]: .state|:ok :- print ""/; [tag: 19]: .state}

Now run it, using the PILS editor window as base for dialogs
(wxWidgets PILS doesn't alow orphan dialogs, they mess up the event 
handling)
!!

  call
  { minix-rules
  | :rule [runner];
    ?window [channel: editor] window;
    ( node [ps] print := "";
      ?endstate
      ([tag: 1]: .state ?:) repeat
      ( minix-rules ---
        { :nonsense | :what rule [runner] :ok what }
        { .print ($ string) | :ok node [ps] print := node [ps] print . 
string }
        { .print ""/
        | :ok
          :if node [ps] print => +$ message;
          :- window wx:MessageBox (message);
          node [ps] print := ""
        }
        { .print (% n)|:self :try self print (?:? write (n)) }
        { .input
        | :if
            window wx:GetTextFromUser (node [ps] print, "minix-input") => +$ 
text,
            ?:? read (text) => % text
          ;
          node [ps] print := "";
          :ok text
        }
! for debugging, a rule can be inserted here.
!        but {state|state bug (?:?)}
      )
      ;
      :ok endstate
    )
    node [ps]
  }
}

!!
This should be a builtin, haven't implemented it yet.
    list split 2   splits a list in pairs, etc.
!!
where
{ & list split (+ splitsize)
| :ok
  list count repeat
  { + count | :ok list() := list <+# count ++# splitsize; count - 
splitsize }
  list()
}


0
Reply ole.nielsby1 (52) 7/18/2007 8:30:27 PM

Mark Tarver wrote:
> This whole post is a commented Qi program so you can load it into Qi.

How do I get a working Qi environment? I can't find a Debian package. Is
there a Lisp equivalent of CPAN or GODI that makes it easy to fetch and
install such things?

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/19/2007 9:40:25 AM

Ole Nielsby wrote:
> Parsing is done with a cheat - using 9 code lines.
> The compiler as such approx. 45 code lines. 

The short interpreter is 63 LOC in OCaml or 133 LOC including the full lexer
and yacc-based parser.

> Execution time for 100000 + 100000 is approx. 1.7 seconds on a
> 2GHz dual core2, using the VC2005 release build of the PILS system.

Not meaning to be rude, but why are the Qi and PILS implementations so slow?

This is just looping and incrementing 100,000 times and you guys are getting
times ~1s? That means you're doing O(10,000) machine operations per loop of
the minim code, which is just crazy.

Mathematica is the slowest language that I have access to and even it only
takes 0.27s to complete this problem:

$ ledit MathKernel
Mathematica 5.1 for Linux x86 (64 bit)
Copyright 1988-2004 Wolfram Research, Inc.
 -- Motif graphics initialized --

In[1]:= x=100000; y=100000;

In[2]:= Timing[While[x>0, --x; ++y]; y]

Out[2]= {0.26896 Second, 200000}

> (Actually, I tested with 1000000 + 1000000 and got 17 seconds.)

That is ~200x slower than the OCaml, which takes only 0.08s:

$ time ./eval.native test.minim <args.txt
Add x and y
Input x: 1000000
Input y: 1000000
The total of x and y is 2000000

real    0m0.080s
user    0m0.078s
sys     0m0.002s

Rewriting the test Minim program in OCaml:

let x = ref 1000000
let y = ref 1000000

let () =
  while !x>0 do
    decr x;
    incr y;
  done;
  Printf.printf "y=%d\n%!" !y

and running it using OCaml's bytecode interpreter takes only 0.004s so it is
20x faster than my naive term-level interpreter, which sounds about right.
I can't imagine what you're doing to make it run another 200 times slower
though...

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/19/2007 10:44:35 AM

On 18 Jul, 06:41, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
> Mark Tarver <dr.mtar...@ukonline.co.uk> writes:
> > The task is to implement an interpreter for a language Minim and run a
> > stock Minim program that adds two numbers x and y together where x =
> > 100000 (10^5) and y = 100000 (10^5) and give the times.
>
> This is too easy to game.  Think of the obvious Lisp approach of
> translating the Minim program into an S-expression and evaluating it.
> Now think of an evaluator that automatically invokes an optimizing
> compiler and memoizes the resulting machine code.  You see where this
> leads.

Ah, but thats a compiler Paul, not an interpreter.

Actually, thats easy in Lisp because Lisp includes many 'impure'
procedural constructions.  I doubt it would be so easy to do in a pure
functional language.

Mark

0
Reply dr.mtarver (661) 7/19/2007 10:45:22 AM

OK; I'm reading this group on one news reader which works but does not
let me post and replying on Google which lets me reply (sometimes) but
does not let me read my own post.  Rather weird - like watching a film
in which the action is out of sync with the sound.  I'm going to
suppose that this ends up where it should.

> This is ok but I think minim is a little too simple.

Well its a post, so I wanted it not to be too long.

> Can you write a parser so the program can be loaded from a text file written
> in the syntax you described? Unfair to hard code it...

Not needed - just place (time (run ....)) into a text file and load it
with type checking enabled.
The type checker will parse the input to ensure it conforms to the
requirements.

> Can you give an example of errors that your static type system catches?

Any syntax error in a Minim program; for example missing a 'then' in
an if-statement.
Any error in my interpreter that comes from getting Minim syntax wrong
or getting
confused over my data structures - e.g. trying to find the value of a
constant.

Mark

0
Reply dr.mtarver (661) 7/19/2007 1:19:01 PM

QUOTE
Not meaning to be rude, but why are the Qi and PILS implementations so
slow?

This is just looping and incrementing 100,000 times and you guys are
getting
times ~1s? That means you're doing O(10,000) machine operations per
loop of
the minim code, which is just crazy.

Mathematica is the slowest language that I have access to and even it
only
takes 0.27s to complete this problem:

let x = ref 1000000
let y = ref 1000000

let () =
while !x>0 do
decr x;
incr y;
done;
Printf.printf "y=%d\n%!" !y

and running it using OCaml's bytecode interpreter takes only 0.004s so
it is
20x faster than my naive term-level interpreter, which sounds about
right.
I can't imagine what you're doing to make it run another 200 times
slower
though...
UNQUOTE

Come on Jon; that's trying it on :).  Of course if you take my Minim
program
and hand compile it into another language - even a slow one like
Mathematica
- it will run faster than my interpreter.  I can hand compile it into
procedural
Lisp and I guarantee it will be blazingly quick.  You can't make
meaningful comparisons
like that.

But you want a faster interpreter than the one I wrote - OK see my
next post.
(You'll undoubtedly see it before I do thanks to Google).

Nice try, but no cigar and early bedtime with no tea.

Mark

PS This has appeared in the right thread but not in exactly the right
place because
Google still thinks its yesterday and therefore Jon has not made any
such post as the
one to which I am replying which according to Google I will not reply
to until tomorrow.
Confused?  Don't worry about it.



0
Reply dr.mtarver (661) 7/19/2007 2:22:46 PM

Mark Tarver wrote:
> Come on Jon; that's trying it on :).  Of course if you take my Minim
> program and hand compile it into another language - even a slow one like
> Mathematica - it will run faster than my interpreter.

I don't understand why you would think that.

> I can hand compile it into procedural Lisp and I guarantee it will be
> blazingly quick.  You can't make meaningful comparisons like that. 

These results are all for interpreters (no hand compiling, except the
hard-coded Minim program in your Qi):

Mark's Qi: 2s
Ole's PILS: 2s
Mathematica: 0.3s
Jon's OCaml: 0.08s

How do you explain the differences?

> But you want a faster interpreter than the one I wrote - OK see my
> next post.
> (You'll undoubtedly see it before I do thanks to Google).
> 
> Nice try, but no cigar and early bedtime with no tea.

I'm waiting. :-)

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/19/2007 3:27:01 PM

On 2007-07-19 10:22:46 -0400, Mark Tarver <dr.mtarver@ukonline.co.uk> said:

> Of course if you take my Minim
> program
> and hand compile it into another language - even a slow one like
> Mathematica
> - it will run faster than my interpreter.  I can hand compile it into
> procedural
> Lisp and I guarantee it will be blazingly quick.  You can't make
> meaningful comparisons
> like that.

You seem to have mistaken Jon for a legitimate, fair minded, 
correspondent to this newsgroup. He is a spammer trying to sell his 
ocaml and f# consulting services. He will never post anything unless it 
shows these two languages, from which he earns his living, in a 
favorable light, whether the comparison is fair or not.

0
Reply Raffael 7/19/2007 5:59:11 PM

Mark Tarver schrieb:
> Actually, thats easy in Lisp because Lisp includes many 'impure'
> procedural constructions.  I doubt it would be so easy to do in a pure
> functional language.

Quite to the contrary.
They don't have to do aliasing or dataflow analysis to do that kind of 
optimization. I'd expect that kind of optimization to happen far more 
early in the development cycle of a compiler, and that it will stay more 
aggressive throughout the compiler's lifetime.

Regards,
Jo
0
Reply jo427 (1164) 7/19/2007 7:47:24 PM

Jon Harrop <jon@ffconsultancy.com> wrote:

> Ole Nielsby wrote:
>> Parsing is done with a cheat - using 9 code lines.
>> The compiler as such approx. 45 code lines.
>
> The short interpreter is 63 LOC in OCaml or 133 LOC including the full 
> lexer
> and yacc-based parser.

The Kvernbitr parser generator (written in PILS) can parse yacc-unfriendly
languages like VB6 and SQL, using a BNF-like syntax. I haven't yet ported
it to the new PILS dialect which I am going to publish soon.

>> Execution time for 100000 + 100000 is approx. 1.7 seconds on a
>> 2GHz dual core2, using the VC2005 release build of the PILS system.
>
> Not meaning to be rude, but why are the Qi and PILS implementations so 
> slow?
> Mathematica is the slowest language that I have access to and even it only
> takes 0.27s to complete this problem

Whereas PILS takes 0.35s using a direct approach (comparable to the
Mathematica snippet you posted):

  (?x 100000 .y 100000)
  repeat {: ?x . [+] .y|:ok ?x . - 1 .y . + 1}
  y

So it's about the same speed as Mathematica - assumig similar CPUs.

The slowness is mostly due to boxing and unifying of numbers. This
makes PILS unfit for serious number crunching, whereas processing of
texts and node trees is quite fast. So the speed depends on what you
use it for. The unified number boxing may be bad for numeric calculations
but it is part of a strategy that makes pattern matching very fast. So it's
a tradeoff by design.

There is still room for improvement though. There are things I could
do to the PILS interpreter to bypass boxing in cases like this - it's just
not a priority now, the language was never meant for number crunching.


0
Reply ole.nielsby1 (52) 7/19/2007 8:03:04 PM

Ole Nielsby wrote:
> Jon Harrop <jon@ffconsultancy.com> wrote:
>> Ole Nielsby wrote:
>> The short interpreter is 63 LOC in OCaml or 133 LOC including the full
>> lexer
>> and yacc-based parser.
> 
> The Kvernbitr parser generator (written in PILS) can parse yacc-unfriendly
> languages like VB6 and SQL, using a BNF-like syntax. I haven't yet ported
> it to the new PILS dialect which I am going to publish soon.

Yes. I tried writing the parser in camlp4 and using streams first but never
got them to work. I'm going to have another hack at a stream-based parser
as it will be much shorter.

>>> Execution time for 100000 + 100000 is approx. 1.7 seconds on a
>>> 2GHz dual core2, using the VC2005 release build of the PILS system.
>>
>> Not meaning to be rude, but why are the Qi and PILS implementations so
>> slow?
>> Mathematica is the slowest language that I have access to and even it
>> only takes 0.27s to complete this problem
> 
> Whereas PILS takes 0.35s using a direct approach (comparable to the
> Mathematica snippet you posted):
> 
>   (?x 100000 .y 100000)
>   repeat {: ?x . [+] .y|:ok ?x . - 1 .y . + 1}
>   y
> 
> So it's about the same speed as Mathematica - assumig similar CPUs.

Argh, I see. You were both running interpreters in interpreted languages. I
should compile the OCaml to interpreted bytecode rather than native code
for a fairer comparison then. In which case I get (neglecting machine
differences):

CLisp: 0.86s
PILS: 0.35s
OCaml: 0.11s

That's much more inline with what I'd expect.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/19/2007 8:07:50 PM

On 19 Jul, 10:40, Jon Harrop <j...@ffconsultancy.com> wrote:
> Mark Tarver wrote:
> > This whole post is a commented Qi program so you can load it into Qi.
>
> How do I get a working Qi environment? I can't find a Debian package. Is
> there a Lisp equivalent of CPAN or GODI that makes it easy to fetch and
> install such things?
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy
> OCaml for Scientistshttp://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet

When Qi first came out it ran only under Windows CLisp and so I used
to
distribute executables.  Since then Qi has been ported to Allegro,
SBCL and
CMUCL and runs under Xnix and Windows.  So I stopped issuing
executables
because the combinations of platforms and OS were too many.  The
download from
Lambda Associates assumes that you've already got one of these Lisps
and
takes it from there.

J. T. Gleason runs a Google open source repository for Qi and he has
written
an installation package for Qi - see http://code.google.com/p/qilang/

The fastest platform is (I think) CMUCL though I haven't timed it
against
my beta release Windows SBCL.

Mark

0
Reply dr.mtarver (661) 7/19/2007 9:50:04 PM

> These results are all for interpreters (no hand compiling, except the
> hard-coded Minim program in your Qi):
>
> Mark's Qi: 2s
> Ole's PILS: 2s
> Mathematica: 0.3s
> Jon's OCaml: 0.08s
>
> How do you explain the differences?

Ok; not majorly important but the 2s is only for Qi under CLisp.Here
is Qi on an experimental SBCL.

This is experimental prerelease support for the Windows platform: use
at your own risk.  "Your Kitten of Death awaits!"

.............................................

(3+) (time (run [
       [print "Add x and y"]
       nl
       [print "Input x: "]
       [input x]
       nl
       [print "Input y: "]
       [input y]
       main
       [if [x = 0] then [goto end] else [goto sub1x]]

       sub1x
       [-- x]
       [++ y]
       [goto main]

       end
       nl
       [print "The total of x and y is "]
       [print y]
       nl]))
Add x and y
Input x: 10000

Input y: 10000

The total of x and y is 20000
Evaluation took:
  6.75 seconds of real time
  0.03125 seconds of user run time
  0.0 seconds of system run time
  0 calls to %EVAL
  0 page faults and
  655,344 bytes consed.
[(@p x 0) (@p y 20000)] : (list (symbol * number))

Sadly the kitten of death gets me after this, because I suppose, its
an experimental port.   At the cost of much pain I could run this
under CMUCL, but I loathe using Linux and its a drag installing 9.0
under my Ubuntu.  But project the above timing by x10 and you're
looking at a ball park figure of 0.3-0.4s under a well-configured
Lisp; that is at least 5 times faster than my 2.0s under CLisp.

But thats not the main issue.  The main thing is that you are
comparing hand-compiled equivalents to my Minim program, written in
native Mathematica and OCaml, to Qi *interpreting* a Minim program.
Not commensurable at all.

Now regarding my Minim program being 'hard-coded'.  I really don't
know what that means here.  Your Mathematica program is certainly hard-
coded.  The Minim program corresponds exactly to the BNF laid down -
its not tweaked at all.

Mark


0
Reply dr.mtarver (661) 7/19/2007 10:24:15 PM

Mark Tarver wrote:

> Sadly the kitten of death gets me after this, because I suppose, its
> an experimental port.  

Maybe.  Turns out that having (tc +) on in qi 7.3 will crash under sbcl
1.0.7 on linux on load of the source of your minim implementation on my
machine, with a joyful and rather unusual "Unhandled memory fault at
#x0."

> At the cost of much pain I could run this
> under CMUCL, but I loathe using Linux

Well, hey, I loathe using Windows.  Strange though.  Are you
sure you loathe using Linux?  Maybe you just loathe a 
particular desktop environment for Linux like GNOME?  If you have
ubuntu, try "apt-get install kubuntu-desktop" (or use the package
management GUI), and select a KDE session instead of a GNOME one upon
next login. 

> Now regarding my Minim program being 'hard-coded'.  I really 
> don't  know what that means here. 

Well, obviously you're not compiling the input expression into the
program which is what "hard coding" would usually suggest to me (like
jon hard coded the input expression into his ml program rather than
reading it at run time in the previous "simplify" example).  He may
have some issue with you supplying the minim program at runtime to the
interpreter as lists though. That's not what I'd call "hard coding".  It
is skipping lexing, or at least reusing the lisp reader's
[sorta-]lexing instead of writing your own, though.  There are of
course lexer packages for use in lisp around, though I haven't used
them much myself, e.g. Michael Parker's 
http://www.geocities.com/mparker762/clawk.html



0
Reply david.golden (499) 7/20/2007 12:27:42 AM

Mark Tarver wrote:
> But thats not the main issue.  The main thing is that you are
> comparing hand-compiled equivalents to my Minim program, written in
> native Mathematica and OCaml, to Qi *interpreting* a Minim program.
> Not commensurable at all.

No, I'm comparing your interpreter to my interpreter (the one I posted).

> Now regarding my Minim program being 'hard-coded'.  I really don't
> know what that means here.  Your Mathematica program is certainly hard-
> coded.

Yes.

> The Minim program corresponds exactly to the BNF laid down - its not
> tweaked at all. 

You gave a BNF:

<program> := <statement>
             | <statement> <program>;
<statement> := <assignment>
                | <conditional>
                | <goto>
....

But it appears that your program does not include a lexer and parser,
instead having the Minim program hard-coded in the Qi source code:

(3+) (time (run [
       [print "Add x and y"]
       nl
       [print "Input x: "]
....

My interpreter loads its input program from the specified text file. I think
that is an important difference in terms of functionality. Perhaps I have
misunderstood.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/20/2007 4:39:09 AM

Turns out that having (tc +) on in qi 7.3 will crash under sbcl
> 1.0.7 on linux on load of the source of your minim implementation on my
> machine, with a joyful and rather unusual "Unhandled memory fault at
> #x0."

Can't comment on this - CLisp compiles and runs it fine.
My 1.0.6 SBCL crashes worse than 1.0 with a different error message.
1.0 sometimes crashes while loading this program and sometimes it
loads it.  I think on balance of probability there is a problem in
SBCL somewhere.   This is why I generally use the slower but more
stable CLisp.  Try it.

>
> > At the cost of much pain I could run this
> > under CMUCL, but I loathe using Linux
>
> Are you> sure you loathe using Linux?  

OK; let me check .... hmmm, yes, yes I do.

> He may
> have some issue with you supplying the minim program at runtime to the
> interpreter as lists though. That's not what I'd call "hard coding".  

Agreed.

> It
> is skipping lexing, or at least reusing the lisp reader's
> [sorta-]lexing instead of writing your own, though.  

OK; that's a different point. Actually Qi has its own lexer and all
the input is going through that. I was not assuming that people needed
to implement a lexer, but that might be needed for certain languages
which be limited to string entry etc.  But my entry corresponds to the
BNF for Minim.

Mark

0
Reply dr.mtarver (661) 7/20/2007 6:17:30 AM

> But it appears that your program does not include a lexer and parser,
> instead having the Minim program hard-coded in the Qi source code:
>
> (3+) (time (run [
>        [print "Add x and y"]
>        nl
>        [print "Input x: "]
> ...
>
> My interpreter loads its input program from the specified text file. I think
> that is an important difference in terms of functionality. Perhaps I have
> misunderstood.

See remark above, just put my line entry into a file and load it.  The
parsing is done by the Qi type checker based on the spec in my
interpreter program.

If you want to seperate out the reading from the execution then define

(define run-minim
  {string --> symbol}
  File -> (time (load File)))

and put (run <put your Minim program here> into the file.

(6+) (run-minim "minim add.txt")
Add x and y
Input x: ... etc.

Hack my Minim program and put in an error (missing then)

[if [x = 0] [goto end] else [goto sub1x]]

(7+) (run-minim "minim add.txt")
error: type error

Mark

0
Reply dr.mtarver (661) 7/20/2007 6:47:45 AM

Mark Tarver wrote:
> Hack my Minim program and put in an error (missing then)
> 
> [if [x = 0] [goto end] else [goto sub1x]]
> 
> (7+) (run-minim "minim add.txt")
> error: type error

Perhaps I am mistaken, but this is not the grammar that you described
because the text file you're loading must be translated into Qi notation by
hand (by adding [ ] etc.)?

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/20/2007 8:20:13 AM

On 20 Jul, 09:20, Jon Harrop <j...@ffconsultancy.com> wrote:
> Mark Tarver wrote:
> > Hack my Minim program and put in an error (missing then)
>
> > [if [x = 0] [goto end] else [goto sub1x]]
>
> > (7+) (run-minim "minim add.txt")
> > error: type error
>
> Perhaps I am mistaken, but this is not the grammar that you described
> because the text file you're loading must be translated into Qi notation by
> hand (by adding [ ] etc.)?
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy
> OCaml for Scientistshttp://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet

If you prefer round brackets, then load it through Lisp.

(run '(etc etc....))

or if you hate the (run '( bit just type in Qi

(1-) (run (read-file "minim program.txt"))

with this in the file

       (print "Add x and y")
       nl
       (print "Input x: ")
       (input x)
       nl
       (print "Input y: ")
       (input y)
       main
       (if (x = 0) then (goto end) else (goto sub1x))

       sub1x
       (-- x)
       (++ y)
       (goto main)

       end
       nl
       (print "The total of x and y is ")
       (print y)
       nl

I probably need to add a typed version of read-file; would be useful.
But that works.

The problem here I think is the OCaml technology.  A Minim program is
just a list of a particular structure.  But languages like ML and its
relatives do not operate kindly with free form lists as does Lisp.  In
this event ML expects you to define constructor functions and if the
original source is not in that form then you need to lex and parse it
into your internal representation.

Qi does not need to do that with Minim because the Qi approach to
typing is designed to be consistent with the Lisp approach to
programming.  No Qi/Lisp programmer will write a Minim lexer that is
effectively nothing more than an identity function w.r.t. the input,
and parsing is not needed in Qi because if the syntax is wrong the Qi
type checker will tell him.

Your adopted religion requires you to operate in this way; like having
to eat cold boiled spinach on Sunday.  But I have no appetite for
eating cold spinach; this is why I left languages like ML, OCaml and
Haskell behind a long time ago.

Mark

0
Reply dr.mtarver (661) 7/20/2007 11:18:36 AM

On Jul 18, 1:24 am, Mark Tarver <dr.mtar...@ukonline.co.uk> wrote:
> \Jon suggested that it would be good to implement some significant
> programs in different functional languages for comparison.  He
> suggested interpreters for procedural languages like Basic.

 Hi there!

 Here is our solution, using the .NET framework and MBase
(see http://www.meta-alternative.net/techpreview.html)

 The compiled code works even faster than corresponding C# code,
compilation time is reasonably small.

-------
;;; Language abstract syntax tree
(def:ast minim ()
  (*TOP* <program>) ;; entry point, used internally
  (program <*statement:sts>)
  (statement
   (| (Ass <ident:var> <val:val>)
      (++ <ident:var>)
      (-- <ident:var>)
      (Cnd <test:tst> <statement:tr> <statement:fl>)
      (Gto <ident:tag>)
      (Tag <ident:tag>)
      (PrntStr <string:val>)
      (PrntVal <val:val>)
      (PrntNl)
      (Input <ident:v>)
      ))
  (test
   (| (Comp cmp <val:left> <val:right>)
      (And <test:left> <test:right>)
      (Or <test:left> <test:right>)
      (Not <test:t>)
      ))
  (val (| (V <ident:v>) (C num)))
  )

;;; Some .NET stuff
(define _print_mtd (r_mtd "System.Console" "Write" object))
(define _readline_mtd (r_mtd "System.Console" "ReadLine"))
(define _parse_mtd (r_mtd "System.Int32" "Parse" string))

;;; Compiler: compiling minim program into .NET IL
(function minim->cli ( expr )
  (<> expr
   (ast:visit minim program
     (program DEEP ;; flatten the compiled statements list
       (foldl append '() sts))
     (statement DEEP ( ;; compile the statement, deeper ones first
       (Ass
	    `((local ,var ,t_Int32)
	      ,@val
	      (Stloc (var ,var))))
       (++ `((Ldloc (var ,var))
	     ,(_ldc_i4 1)
	     (Add)
	     (Stloc (var ,var))))
       (-- `((Ldloc (var ,var))
	     ,(_ldc_i4 1)
	     (Sub)
	     (Stloc (var ,var))))
       (Cnd
	(with-syms (lend lfl)
	  `(,@tst
	    (Brfalse (label ,lfl))
	    ,@tr
	    (Br (label ,lend))
	    (label ,lfl)
	    ,@fl
	    (label ,lend)
	    )))
       (Gto `((Br (label ,tag))))
       (Tag `((label ,tag)))
       (PrntStr
	    `((Ldstr ,val) (Call ,_print_mtd)))
       (PrntVal
	    `(,@val (Box ,t_Int32)
	      (Call ,_print_mtd)))
       (PrntNl
	 `((Ldstr "\n") (Call ,_print_mtd)))
       (Input
	 `((local ,v ,t_Int32)
           (Call ,_readline_mtd)
	   (Call ,_parse_mtd)
	   (Stloc (var ,v))))))
     (val DEEP ( ;; compile the value lookup
       (V `((Ldloc (var ,v))))
       (C `(,(_ldc_i4 num)))))
     (test DEEP ( ;; compile the test statement
       (Comp
             `(,@left ,@right
	       ,(case cmp ((>) '(Cgt)) ((<) '(Clt)) ((=) '(Ceq)))))
       (And  `(,@left ,@right (And)))
       (Or   `(,@left ,@right (Or)))
       (Not  `(,t (Not)))))
     )))

;;; Being fair: won't reuse s-expressions parser,
;;; implementing a real one, with an advantage of
;;; readable error messages.

;; Simple lexer: splits the stream into tokens
(make-simple-lexer minim-lexer
  (ident-or-keyword
   (p.alpha ((p.alpha | p.digit) *))
    ident)
  (keywords input print nl goto if then else and or not is)
  (simple-tokens
   "[" LB "]" RB
   "(" LB ")" RB
   ">" > "<" < "=" = "++" ++ "--" --)
  (regexp-tokens
   (("\"" (((#\\ #\") | (! #\")) *) "\"") ->
    (M@ list->string cuttail cdr)) string
   (("\'" (((#\\ #\') | (! #\')) *) "\'") ->
    (M@ list->string cuttail cdr)) string
   p.integer.p                     number)
  (ignore p.whitespace))

;; Simple LL(1) parser
(bnf-parser ((programg parse-minim))

  (programg
   ((LB program RB) $1) ;; not quite conforming to formal spec,
                        ;; but required to run the test prog.
   )
  (program
   ((statement program) (cons $0 $1))
   ((statement) (list $0)))

  (statement
   ((LB ident:va is val:vl RB) `(Ass ,va ,vl))
   ((LB ++ ident:va RB) `(++ ,va))
   ((LB -- ident:va RB) `(-- ,va))
   ((LB goto ident:tag  RB) `(Gto ,tag))
   ((LB if test:tst then statement:s1 else statement:s2 RB)
    `(Cnd ,tst ,s1 ,s2))
   ((LB print string:str RB)
    `(PrntStr ,str))
   ((LB print val:v RB)
    `(PrntVal ,v))
   ((nl)
    `(PrntNl))
   ((LB input ident:va RB)
    `(Input ,va))
   ((ident)
    `(Tag ,$0)))

  (val
   ((ident) `(V ,$0))
   ((number) `(C ,$0)))

  (test
   ((LB val:v1 comp:c val:v2 RB) `(Comp ,c ,v1 ,v2))
   ((LB test:l and test:r RB) `(And ,l ,r))
   ((LB test:l or test:r RB) `(Or ,l ,r))
   ((LB not test:t RB) `(Not ,t)))

  (comp
   ((<) '<)
   ((>) '>)
   ((=) '=))
  )

;; Compiler frontend: macro which embedds the compiled IL assebmly
;; into the Lisp function and calls that function immediately.
;; In case of an error it prints the message, doing nothing.
(macro include-minim (fname)
  (try
   (let* ((ll (lex-and-parse minim-lexer parse-minim
			     (read-file-list fname)))
	  (lp (minim->cli ll))
	  (nm (gensym)))
     `(begin
	(function ,nm ()
           (n.asm ()
	   ,@lp
	   (Ldnull)
	   ))
	(,nm)
	))
   t_MBaseException
   (fun (e)
     (writeline `(Exception in minim loader: ,(mbaseerror e)))
     'nil)))

;; Now: test it.
(include-minim "test1.min")


0
Reply info3535 (6) 7/20/2007 11:30:45 AM

P.S.: in order to build standalone Minim executables,
change the last macro into the following:

;; Compiler frontend: macro which embedds the compiled IL assebmly
;; into the Lisp function and calls that function immediately.
;; In case of an error it prints the message, doing nothing.
(macro include-minim-f (nm fname)
  (try
   (let* ((ll (lex-and-parse minim-lexer parse-minim
			     (read-file-list fname)))
	  (lp (minim->cli ll)))
     `(function ,nm ()
	(n.asm ()
         ,@lp
	 (Ldnull)
	 )
	))
   t_MBaseException
   (fun (e)
     (writeline `(Exception in minim loader: ,(mbaseerror e)))
     'nil)))

(macro include-minim ( fname )
  (with-syms ( nm )
    `(top-begin
       (include-minim-f ,nm ,fname)
       (,nm))))

----

 And compile now the following file (using mbase /compiledll
<filename>):

(n.module mcomp exe)

(include "./minim.al")

;;; MINIM language compiler frontend for standalone executables.

(function main ( )
  (let ((fnm (car (a->l *CMDLINE*))))
    (read-int-eval '(n.module minim exe))
    (read-compile-eval
     `(include-minim-f main ,fnm))
    (read-int-eval '(save-module))
    ))

----

 After that, just do "mcomp ./test1.min", and "minim.exe" to run the
resulting program.

0
Reply info3535 (6) 7/20/2007 1:05:34 PM

Mark Tarver <dr.mtarver@ukonline.co.uk> writes:

> Qi does not need to do that with Minim because the Qi approach to
> typing is designed to be consistent with the Lisp approach to
> programming.  No Qi/Lisp programmer will write a Minim lexer that is
> effectively nothing more than an identity function w.r.t. the input,
> and parsing is not needed in Qi because if the syntax is wrong the Qi
> type checker will tell him.

I think you are being unfair here.  Clearly, you designed the language
specifically so that it can be parsed trivially using Lisp.
(Well, at least as long as you allow an extra pair of parentheses
around your program -- something that the original grammar you posted
did not.)
And, strangely, you don't even stick to that syntax but use a
different one in your Qi implementation...

> Your adopted religion requires you to operate in this way; like having
> to eat cold boiled spinach on Sunday.  But I have no appetite for
> eating cold spinach; this is why I left languages like ML, OCaml and
> Haskell behind a long time ago.

Well, Jon may come across as a bit nutty at times, but at least he
restricts his spinach-eating to Sundays.

IMNSHO, to be on level playing ground, the syntax of the language to
be interpreted should not blatantly favor one of the contestants.
Or would you agree to a syntax that happens to match, say, Haskell
data syntax?  Haskell programmers would have a huge advantage, since
they would just declare the data types for the abstract syntax, add
"deriving Read", and be done with the parser...

Cheers,
Matthias
0
Reply blume (6) 7/20/2007 2:50:09 PM

Mark Tarver wrote:
> The problem here I think is the OCaml technology...

Allow me to cripple the OCaml, making it as featureless as the Lisp:

module Bindings = Map.Make(String)

let set m x y = Bindings.add x y m
let get m x = Bindings.find x m

let tags_of program =
  let aux (pc, tags) = function
    | `Tag t -> pc+1, Bindings.add t pc tags
    | _ -> pc+1, tags in
  let _, tags = Array.fold_left aux (0, Bindings.empty) program in
  tags

let eval vars = function
  | `Lit n -> n
  | `Var v -> get vars v

let rec test vars = function
  | `Less(f, g) -> eval vars f < eval vars g
  | `Equal(f, g) -> eval vars f = eval vars g
  | `Greater(f, g) -> eval vars f > eval vars g
  | `And(f, g) -> test vars f && test vars g
  | `Or(f, g) -> test vars f || test vars g
  | `Not f -> not(test vars f)

let rec statement tags vars pc = function
  | `Assign(x, y) -> set vars x (eval vars y), pc + 1
  | `Incr x -> set vars x (get vars x + 1), pc + 1
  | `Decr x -> set vars x (get vars x - 1), pc + 1
  | `If(p, t, f) -> statement tags vars pc (if test vars p then t else f)
  | `Goto tag -> vars, Bindings.find tag tags
  | `Tag _ -> vars, pc + 1
  | `PrintString s -> print_string s; vars, pc + 1
  | `Print x -> print_int(get vars x); vars, pc + 1
  | `Input x -> set vars x (int_of_string(input_line stdin)), pc + 1

let rec run program tags (vars, pc) =
  run program tags (statement tags vars pc program.(pc))

let () =
  run
    [|PrintString "Add x and y"; PrintString "\n"; PrintString "Input x: ";
      Input "x"; PrintString "\n"; PrintString "Input y: "; Input "y";
      Tag "main"; If (Equal (Var "x", Lit 0), Goto "end", Goto "sub1x");
      Tag "sub1x"; Decr "x"; Incr "y"; Goto "main"; Tag "end";
      PrintString "\n"; PrintString "The total of x and y is "; Print "y";
      PrintString "\n"|]
    (tags_of program) (Bindings.empty, 0)

> Your adopted religion requires you to operate in this way...

As you can see, the OCaml operates perfectly well both ways. The Lisp,
however, does not.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/20/2007 2:54:07 PM

Matthias Blume wrote:
> Mark Tarver <dr.mtarver@ukonline.co.uk> writes:
>> Qi does not need to do that with Minim because the Qi approach to
>> typing is designed to be consistent with the Lisp approach to
>> programming.  No Qi/Lisp programmer will write a Minim lexer that is
>> effectively nothing more than an identity function w.r.t. the input,
>> and parsing is not needed in Qi because if the syntax is wrong the Qi
>> type checker will tell him.
> 
> I think you are being unfair here...

It would be unfair to compare the similar-sized Lisp and OCaml
implementations when only the OCaml implements a lexer and parser. Provided
you strip the lexer and parser from the OCaml, I think it is fair. The
OCaml remains several times faster and is now several times shorter as
well.

I think it is a shame that Mark backtracked from a description of the
grammar only to hard-code the interpreted program in the interpreter. I
would have liked to see a lexer and parser written in Lisp. Now I can only
assume that it is prohibitively difficult to implement such trivial
functionality correctly in Lisp.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/20/2007 3:01:43 PM

On 20 Jul, 15:50, Matthias Blume <bl...@hanabi.local> wrote:
> Mark Tarver <dr.mtar...@ukonline.co.uk> writes:
> > Qi does not need to do that with Minim because the Qi approach to
> > typing is designed to be consistent with the Lisp approach to
> > programming.  No Qi/Lisp programmer will write a Minim lexer that is
> > effectively nothing more than an identity function w.r.t. the input,
> > and parsing is not needed in Qi because if the syntax is wrong the Qi
> > type checker will tell him.
>
> I think you are being unfair here.  Clearly, you designed the language
> specifically so that it can be parsed trivially using Lisp.
> (Well, at least as long as you allow an extra pair of parentheses
> around your program -- something that the original grammar you posted
> did not.)
> And, strangely, you don't even stick to that syntax but use a
> different one in your Qi implementation...
>
> > Your adopted religion requires you to operate in this way; like having
> > to eat cold boiled spinach on Sunday.  But I have no appetite for
> > eating cold spinach; this is why I left languages like ML, OCaml and
> > Haskell behind a long time ago.
>
> Well, Jon may come across as a bit nutty at times, but at least he
> restricts his spinach-eating to Sundays.
>
> IMNSHO, to be on level playing ground, the syntax of the language to
> be interpreted should not blatantly favor one of the contestants.
> Or would you agree to a syntax that happens to match, say, Haskell
> data syntax?  Haskell programmers would have a huge advantage, since
> they would just declare the data types for the abstract syntax, add
> "deriving Read", and be done with the parser...
>
> Cheers,
> Matthias

Ah, that's quite legitimate, but not the point Jon is making.  Jon is
saying 'Where's your lexer?' and I'm saying 'Actually Qi doesn't need
one here for this example' - the lexer is the identity function.
Properly
then we can level the field by taking out his lexer
from LOC and the timings and that would be fine by me.
More sensible than requiring me to write a lexer that does nothing -
that's very dull :(.  And the parsing is done by the Qi type checker.

The rest of his complaint about needing []s and run is easily solved
(see my reply to him).

Mark


0
Reply dr.mtarver (661) 7/20/2007 6:13:16 PM

On 19 Jul, 20:47, Joachim Durchholz <j...@durchholz.org> wrote:
> Mark Tarver schrieb:
>
> > Actually, thats easy in Lisp because Lisp includes many 'impure'
> > procedural constructions.  I doubt it would be so easy to do in a pure
> > functional language.
>
> Quite to the contrary.
> They don't have to do aliasing or dataflow analysis to do that kind of
> optimization. I'd expect that kind of optimization to happen far more
> early in the development cycle of a compiler, and that it will stay more
> aggressive throughout the compiler's lifetime.
>
> Regards,
> Jo

\I don't reckon so; Lisp is a very easy target for *compiling* Minim.
Here's the code which runs under the Qi environment.  It takes a Minim
program in one file and outputs the corresponding Lisp to be LOADed
into Qi.\

(define compile-minim-to-lisp
  In Out -> (write-to-file Out
               [TIME [BLOCK [] [TAGBODY | (map compile-statement (read-
file In))]]]))

(define compile-statement
  [++ V] -> [INCF V]
  [-- V] -> [DECF V]
  [goto Tag] -> [GO Tag]
  [if X then Y else Z] -> [if (compile-test X)
                              (compile-statement Y)
                              (compile-statement Z)]
  [input V] -> [SETQ V [READ]]
  [print Message] -> [FORMAT T "~A" Message]
  [Var is Val] -> [SETQ Var Val]
  nl -> [TERPRI]
  Tag -> Tag)

(define compile-test
  [X > Y] -> [> X Y]
  [X = Y] -> [= X Y]
  [X < Y] -> [< X Y]
  [P and Q] -> [and (compile-test P) (compile-test Q)]
  [P or Q] -> [or (compile-test P) (compile-test Q)]
  [not P] -> [not (compile-test P)]
  P -> P)

\The compiled output of this program uses Qi booleans but can be
LOADED into Qi just like any other Lisp program.

(14-) (compile-minim-to-lisp "f.txt" "g.txt")
"g.txt"

(15-) (COMPILE-FILE "g.txt")
P"C:Documents and Settings/User/My Documents/Qi 9.0/g.fas"

(16-) (LOAD "g")

Add x and y
Input x: 100000

Input y: 100000

The total of x and y is 200000

Real time: 12.140625 sec.
Run time: 0.046875 sec.

About 50X faster than my interpreter - even under CLisp.

It is easy for precisely the reason I gave; because Lisp includes
these impure procedural features as part of the language spec.

This is too trivial as a challenge problem and too biased to Lisp,
hence I didn't set it.

Mark\

0
Reply dr.mtarver (661) 7/20/2007 9:43:27 PM

Jon Harrop <jon@ffconsultancy.com> writes:

> Mark Tarver wrote:
>> The problem here I think is the OCaml technology...
>
> Allow me to cripple the OCaml, making it as featureless as the Lisp:
>
> module Bindings = Map.Make(String)
>
> let set m x y = Bindings.add x y m
> let get m x = Bindings.find x m
>
> let tags_of program =
>   let aux (pc, tags) = function
>     | `Tag t -> pc+1, Bindings.add t pc tags
>     | _ -> pc+1, tags in
>   let _, tags = Array.fold_left aux (0, Bindings.empty) program in
>   tags
>
> let eval vars = function
>   | `Lit n -> n
>   | `Var v -> get vars v
>
> let rec test vars = function
>   | `Less(f, g) -> eval vars f < eval vars g
>   | `Equal(f, g) -> eval vars f = eval vars g
>   | `Greater(f, g) -> eval vars f > eval vars g
>   | `And(f, g) -> test vars f && test vars g
>   | `Or(f, g) -> test vars f || test vars g
>   | `Not f -> not(test vars f)
>
> let rec statement tags vars pc = function
>   | `Assign(x, y) -> set vars x (eval vars y), pc + 1
>   | `Incr x -> set vars x (get vars x + 1), pc + 1
>   | `Decr x -> set vars x (get vars x - 1), pc + 1
>   | `If(p, t, f) -> statement tags vars pc (if test vars p then t else f)
>   | `Goto tag -> vars, Bindings.find tag tags
>   | `Tag _ -> vars, pc + 1
>   | `PrintString s -> print_string s; vars, pc + 1
>   | `Print x -> print_int(get vars x); vars, pc + 1
>   | `Input x -> set vars x (int_of_string(input_line stdin)), pc + 1
>
> let rec run program tags (vars, pc) =
>   run program tags (statement tags vars pc program.(pc))
>
> let () =
>   run
>     [|PrintString "Add x and y"; PrintString "\n"; PrintString "Input x: ";
>       Input "x"; PrintString "\n"; PrintString "Input y: "; Input "y";
>       Tag "main"; If (Equal (Var "x", Lit 0), Goto "end", Goto "sub1x");
>       Tag "sub1x"; Decr "x"; Incr "y"; Goto "main"; Tag "end";
>       PrintString "\n"; PrintString "The total of x and y is "; Print "y";
>       PrintString "\n"|]
>     (tags_of program) (Bindings.empty, 0)
>

Did you actually try to compile this code?  It does not look right.
(Unbound variable "program").

0
Reply blume (6) 7/21/2007 2:02:34 AM

Matthias Blume wrote:
> Did you actually try to compile this code?  It does not look right.
> (Unbound variable "program").

No, I was gedankencoding. :-)

Try this:

let () =
  let program =
    [|PrintString "Add x and y"; PrintString "\n"; PrintString "Input x: ";
      Input "x"; PrintString "\n"; PrintString "Input y: "; Input "y";
      Tag "main"; If (Equal (Var "x", Lit 0), Goto "end", Goto "sub1x");
      Tag "sub1x"; Decr "x"; Incr "y"; Goto "main"; Tag "end";
      PrintString "\n"; PrintString "The total of x and y is "; Print "y";
      PrintString "\n"|] in
  run program (tags_of program) (Bindings.empty, 0)

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/21/2007 7:16:38 AM

Mark Tarver wrote:
> > Can you give an example of errors that your static type system catches?
> 
> Any syntax error in a Minim program; for example missing a 'then' in
> an if-statement.

With the program hard-coded, such errors will be caught by OCaml's static
type system. When the program is lexed and parsed properly, the parser
would have caught that error.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/21/2007 8:02:05 AM

Mark Tarver schrieb:
> On 19 Jul, 20:47, Joachim Durchholz <j...@durchholz.org> wrote:
>> Mark Tarver schrieb:
>>
>>> Actually, [evaluating expressions at compile time is] easy in
>>> Lisp because Lisp includes many 'impure' procedural
>>> constructions.  I doubt it would be so easy to do in a pure 
>>> functional language.
 >>
>> Quite to the contrary.
>> They don't have to do aliasing or dataflow analysis to do that kind of
>> optimization. I'd expect that kind of optimization to happen far more
>> early in the development cycle of a compiler, and that it will stay more
>> aggressive throughout the compiler's lifetime.
> 
> \I don't reckon so; Lisp is a very easy target for *compiling* Minim.

Now that's another topic.
I was specifically responding to the "preevaluate at compile time" bit, 
now you're talking about - what? Lisp being useful as a target language?

(Maybe I misunderstood your original statement.)

Regards,
Jo
0
Reply jo427 (1164) 7/21/2007 8:38:10 AM

Mark Tarver wrote:
> Run time: 0.046875 sec.
>
> About 50X faster than my interpreter - even under CLisp.

Then its performance is comparable to my OCaml interpreter (0.043s). Note
that this isn't surprising because this benchmark only tests a part of
CLisp that is about the size of my interpreter (scaled by the relative
verbosity of Lisp, of course).

> It is easy for precisely the reason I gave; because Lisp includes
> these impure procedural features as part of the language spec.

So you're saying Lisp might beat Haskell? That's great but don't forget: its
the taking part that counts.

> This is too trivial as a challenge problem and too biased to Lisp,
> hence I didn't set it.

I'm not sure that this is biased towards Lisp. I'd write a Minim -> C
compiler in OCaml...

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/21/2007 9:40:30 AM

>  you're talking about - what? Lisp being useful as a target language?
>
> (Maybe I misunderstood your original statement.)

Exactly - that is what I as talking about.

Mark

0
Reply dr.mtarver (661) 7/21/2007 12:41:03 PM

I finally managed to get a version working using the new camlp4 system to
implement an in-line extensible parser. The result is a 68-line interpreter
that runs more quickly than all other implementations so far:

open Camlp4.Sig;;
open Camlp4.Struct;;

let tags = ref [] and vars = ref [];;
let rec get m k =
  try List.assoc k !m with Not_found -> m := (k, ref 0) :: !m; get m k

let pc = ref 0;;

module Token = Token.Make(Loc);;
module Lexer = Lexer.Make(Token);;
module Gram = Grammar.Static.Make(Lexer);;

let program = Gram.Entry.mk "program";;
let program_aux = Gram.Entry.mk "program_aux";;
let statement = Gram.Entry.mk "statement";;
let value = Gram.Entry.mk "value";;
let test = Gram.Entry.mk "test";;
let comp = Gram.Entry.mk "comp";;

EXTEND Gram
  program:
  [ [ ss=LIST1 program_aux -> Array.of_list ss ] ];
  program_aux:
  [ [ s=statement -> incr pc; s ] ];
  statement:
  [ [ x=LIDENT; "is"; y=value -> `Assign(get vars x, y)
    | "++"; x=LIDENT -> `Incr(get vars x)
    | "--"; x=LIDENT -> `Decr(get vars x) ]
  | [ "if"; p=test; "then"; t=statement; "else"; f=statement -> `If(p, t,
f) ]
  | [ "goto"; t=LIDENT -> `Goto(get tags t) ]
  | [ t=LIDENT; s=statement -> get tags t := !pc; s ]
  | [ "print"; s=STRING -> `PrintString s
    | "print"; v=value -> `Print v
    | "nl" -> `PrintString "\n" ]
  | [ "input"; x=LIDENT -> `Input(get vars x) ] ];
  value:
  [ [ x=LIDENT -> `Var(get vars x)
    | n=INT -> `Int(int_of_string n) ] ];
  test:
  [ [ a=value; op=comp; b=value -> `Comp(op, a, b) ]
  | [ a=test; "and"; b=test -> `And(a, b) ]
  | [ a=test; "or"; b=test -> `Or(a, b) ]
  | [ "not"; a=test -> `Not a ] ];
  comp:
  [ [ "<" -> `Less | "=" -> `Equal | ">" -> `Greater ] ];
END;;

let eval = function `Int n -> (n : int) | `Var v -> !v

let rec test = function
  | `Comp(`Less, f, g) -> eval f < eval g
  | `Comp(`Equal, f, g) -> eval f = eval g
  | `Comp(`Greater, f, g) -> eval f > eval g
  | `And(f, g) -> test f && test g
  | `Or(f, g) -> test f || test g
  | `Not f -> not(test f)

let rec statement pc = function
  | `Assign(x, y) -> x := eval y; pc + 1
  | `Incr x -> incr x; pc + 1
  | `Decr x -> decr x; pc + 1
  | `If(p, t, f) -> statement pc (if test p then t else f)
  | `Goto tag -> !tag
  | `PrintString s -> print_string s; pc + 1
  | `Print x -> print_int(eval x); pc + 1
  | `Input x -> x := int_of_string(input_line stdin); pc + 1

let rec run program pc = run program (statement pc program.(pc))

let () =
  match Sys.argv with
  | [|_; file|] ->
      let ch = open_in file in
      let program = Gram.parse program Loc.ghost (Stream.of_channel ch) in
      close_in ch;
      (try run program 0 with _ -> ())
  | _ -> invalid_arg "Usage: ./minim <file>"

I think it is particularly interesting to note that the parser is shorter,
faster and more extensible than the Qi implementation even though the
target grammar is an s-expr!

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/22/2007 10:54:05 AM

Mark Tarver wrote:
> On 18 Jul, 06:41, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
>> Mark Tarver <dr.mtar...@ukonline.co.uk> writes:
>>> The task is to implement an interpreter for a language Minim and run a
>>> stock Minim program that adds two numbers x and y together where x =
>>> 100000 (10^5) and y = 100000 (10^5) and give the times.
>> This is too easy to game.  Think of the obvious Lisp approach of
>> translating the Minim program into an S-expression and evaluating it.
>> Now think of an evaluator that automatically invokes an optimizing
>> compiler and memoizes the resulting machine code.  You see where this
>> leads.
> 
> Ah, but thats a compiler Paul, not an interpreter.

....and why would that matter?!?

[The following should be quite fast - but I haven't performed any test 
runs. I am interested in your results, though. It should be possible to 
squeeze out more by adding declarations...]


(defvar *tag-table* '())
(defvar *var-table* '())

(defun eval-statements (statement more-statements)
   (flet ((cont ()
            (when more-statements
              (eval-statements
                (car more-statements)
                (cdr more-statements)))))
     (etypecase statement
       (symbol (if (eq statement 'nl)
                 (terpri)
                 (setf (getf *tag-table* statement)
                       (cons statement more-statements)))
               (cont))
       (cons (case (car statement)
               (if (destructuring-bind
                       (<if> test <then> then <else> else) statement
                     (declare (ignore <if>))
                     (assert (and (eq <then> 'then) (eq <else> 'else)))
                     (if (eval-test test)
                       (eval-statements then more-statements)
                       (eval-statements else more-statements))))
               (goto (destructuring-bind
                         (<goto> tag) statement
                       (declare (ignore <goto>))
                       (let ((continuation
                               (or (getf *tag-table* tag)
                                   (member tag more-statements))))
                         (eval-statements
                           (car continuation) (cdr continuation)))))
               (print (destructuring-bind
                          (<print> value) statement
                        (declare (ignore <print>))
                        (princ (eval-value value))
                        (finish-output)
                        (cont)))
               (input (destructuring-bind
                          (<input> var) statement
                        (declare (ignore <input>))
                        (assert (symbolp var))
                        (setf (getf *var-table* var) (read))
                        (cont)))
               (++ (destructuring-bind
                       (<++> var) statement
                     (declare (ignore <++>))
                     (assert (symbolp var))
                     (incf (getf *var-table* var))
                     (cont)))
               (-- (destructuring-bind
                       (<--> var) statement
                     (declare (ignore <-->))
                     (assert (symbolp var))
                     (decf (getf *var-table* var))
                     (cont)))
               (otherwise (destructuring-bind
                              (var1 <is> var2) statement
                            (assert (and (symbolp var1)
                                         (eq <is> 'is)
                                         (symbolp var2)))
                            (setf (getf *var-table* var1)
                                  (getf *var-table* var2))
                            (cont))))))))

(defun eval-value (value)
   (typecase value
     (symbol (getf *var-table* value))
     (otherwise (assert (atom value)) value)))

(defun eval-test (test)
   (if (eq (car test) 'not)
     (destructuring-bind (<not> test) test
       (declare (ignore <not>))
       (not (eval-test test)))
     (destructuring-bind (arg1 op arg2) test
       (ecase op
         (> (> (eval-value arg1) (eval-value arg2)))
         (< (< (eval-value arg1) (eval-value arg2)))
         (= (= (eval-value arg1) (eval-value arg2)))
         (and (and (eval-test arg1) (eval-test arg2)))
         (or (or (eval-test arg1) (eval-test arg2)))))))

(defun eval-minim (statements)
   (eval-statements (car statements) (cdr statements)))

(define-compiler-macro eval-minim (&whole whole statements)
   (unless (and (consp statements) (eq (car statements) 'quote))
     (return-from eval-minim whole))
   (let ((variables '()))
     (labels ((translate-statement (statement)
                (etypecase statement
                  (symbol (if (eq statement 'nl) '(terpri) statement))
                  (cons (case (car statement)
                          (if (destructuring-bind
                                  (<if> test <then> then <else> else)
                                  statement
                                (declare (ignore <if>))
                                (assert (and (eq <then> 'then)
                                             (eq <else> 'else)))
                                `(if ,(translate-test test)
                                   ,(translate-statement then)
                                   ,(translate-statement else))))
                          (goto (destructuring-bind
                                    (<goto> tag) statement
                                  (declare (ignore <goto>))
                                  `(go ,tag)))
                          (print (destructuring-bind
                                     (<print> value) statement
                                   (declare (ignore <print>))
                                   `(progn
                                      (princ ,(translate-value value))
                                      (finish-output))))
                          (input (destructuring-bind
                                     (<input> var) statement
                                   (declare (ignore <input>))
                                   (assert (symbolp var))
                                   (pushnew var variables)
                                   `(setq ,var (read))))
                          (++ (destructuring-bind
                                  (<++> var) statement
                                (declare (ignore <++>))
                                (assert (symbolp var))
                                (pushnew var variables)
                                `(incf ,var)))
                          (-- (destructuring-bind
                                  (<--> var) statement
                                (declare (ignore <-->))
                                (assert (symbolp var))
                                (pushnew var variables)
                                `(decf ,var)))
                          (otherwise (destructuring-bind
                                         (var1 <is> var2) statement
                                       (assert (and (symbolp var1)
                                                    (eq <is> 'is)
                                                    (symbolp var2)))
                                       (pushnew var1 variables)
                                       (pushnew var2 variables)
                                       `(setq ,var1 ,var2)))))))
              (translate-test (test)
                (if (eq (car test) 'not)
                  (destructuring-bind (<not> test) test
                    (declare (ignore <not>))
                    `(not ,(translate-test test)))
                  (destructuring-bind (arg1 op arg2) test
                    (ecase op
                      ((> < =) `(,op ,(translate-value arg1)
                                     ,(translate-value arg2)))
                      ((and or) `(,op ,(translate-test arg1)
                                      ,(translate-test arg2)))))))
              (translate-value (value)
                (when (symbolp value) (pushnew value variables))
                (assert (atom value)) value))
       (let ((new-statements
               (mapcar #'translate-statement (cadr statements))))
         `(prog ,variables ,@new-statements)))))

(defun test-minim ()
   (eval-minim
    '((print "Add x and y")
      nl
      (print "Input x: ")
      (input x)
      nl
      (print "Input y: ")
      (input y)
      nl
      main
      (if (x = 0) then (goto end) else (goto sub1x))

      sub1x
      (-- x)
      (++ y)
      (goto main)

      end
      nl
      (print "The total of x and y is ")
      (print y)
      nl)))

;-)


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/22/2007 1:29:55 PM

Pascal Costanza wrote:
> Mark Tarver wrote:
>> On 18 Jul, 06:41, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
>>> Mark Tarver <dr.mtar...@ukonline.co.uk> writes:
>>>> The task is to implement an interpreter for a language Minim and run a
>>>> stock Minim program that adds two numbers x and y together where x =
>>>> 100000 (10^5) and y = 100000 (10^5) and give the times.
>>> This is too easy to game.  Think of the obvious Lisp approach of
>>> translating the Minim program into an S-expression and evaluating it.
>>> Now think of an evaluator that automatically invokes an optimizing
>>> compiler and memoizes the resulting machine code.  You see where this
>>> leads.
>>
>> Ah, but thats a compiler Paul, not an interpreter.
> 
> ...and why would that matter?!?
> 
> [The following should be quite fast - but I haven't performed any test 
> runs. I am interested in your results, though. It should be possible to 
> squeeze out more by adding declarations...]

....squeeze out more efficiency, I mean...

> (defvar *tag-table* '())

I just noticed that there is a bug in the handling of the *tag-table*, 
but that should be easy to fix...


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/22/2007 3:06:38 PM

Pascal Costanza wrote:
> ...and why would that matter?!?

Indeed.

> [The following should be quite fast - but I haven't performed any test
> runs. I am interested in your results, though. It should be possible to
> squeeze out more by adding declarations...]

By my measurements, this is 2-3x longer and twice as fast as the fastest
OCaml interpreter. By the looks of the code it is using a macro to
translate to Lisp and then compiling, in which case I am surprised the
performance is not better. I assume it is doing a very simple translation
to rather inefficient Lisp?

I'll code up an OCaml equivalent. Should be a good test of the new camlp4
although I'm not sure how to translate the gotos into OCaml...

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/22/2007 3:44:13 PM

Jon Harrop wrote:
> Pascal Costanza wrote:
>> ...and why would that matter?!?
> 
> Indeed.
> 
>> [The following should be quite fast - but I haven't performed any test
>> runs. I am interested in your results, though. It should be possible to
>> squeeze out more by adding declarations...]
> 
> By my measurements, this is 2-3x longer and twice as fast as the fastest
> OCaml interpreter. By the looks of the code it is using a macro to
> translate to Lisp and then compiling, in which case I am surprised the
> performance is not better. I assume it is doing a very simple translation
> to rather inefficient Lisp?

Yes. As I said, there are no type declarations in the generated code. It 
should be straightforward to declare all variables as integers, but then 
all incoming values from (input var) forms have to be type checked. If 
you insist, I can make the necessary changes.

What is neat about this solution here is that the interpreter is still 
available, so you can call eval-minim on computed values as well. The 
translation to Lisp code only occurs at compile time when the compiler 
macro sees a constant value for the program passed to eval-minim, so you 
get the advantages of both an interpreter and a compiler. This is a 
standard practice for optimizing code in Common Lisp, BTW. (To put it 
differently, compiler macros allow you to define ad hoc partial 
evaluations that can take advantage of domain-specific knowledge.)

It is possible to perform the translation to Lisp code on the fly, by 
performing manual dynamic compilation. Then the translation could also 
be done on computed values (but the runtime would be increased by the 
compilation time itself, so a real gain in overall efficiency is much 
harder to achieve this way). This would require a lot more code, though.

> I'll code up an OCaml equivalent. Should be a good test of the new camlp4
> although I'm not sure how to translate the gotos into OCaml...

A standard way to express gotos in functional languages is to turn each 
tag into a function which ends in a call to the immediately following 
tag. If your language is tail recursive, there is no real difference to 
a goto in that case.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/22/2007 4:12:30 PM

Jon Harrop schrieb:
> I finally managed to get a version working using the new camlp4 system to
> implement an in-line extensible parser. The result is a 68-line interpreter
> that runs more quickly than all other implementations so far:
> 
> I think it is particularly interesting to note that the parser is shorter,
> faster and more extensible than the Qi implementation even though the
> target grammar is an s-expr!

The question is what you mean with "shorter".
In principle you can express a problem exactly the same in Lisp as you
could in OCaml (or Haskell).
These languages offer two interesting features: syntactic sugar for a
small set of lambdas (currying) and patter matching. Haskell also offers
lazyness which reduces the need for some macros (and can result in worse
performance).
On top of that there is not really much more that one can find in for
example OCaml. Currying and PM are also available in Lisp. In Lisp there
also is a dynamic environment and macros. These macros can also access
the Lisp environment at run time (well, any Lisp programming always
happens at runtime).
So, from that we know that in principle Lisp programs should be the same
(or shorter), complexity wise.

Counting lines makes not much sense for Lisp. Although it supports all
these programming paradigms it has a very unique style which will blow
up the LOC count in several cases. But from this it doesn't follow, that
coding takes longer.

This one liner:  (defun make-accumulator (n) (lambda (i) (incf n i)))
gets usually written in three visible lines:
(defun make-accumulator (n)
   (lambda (i)
     (incf n i)))

OCaml has a lot of syntax which allows generally to express algorithms
with a smaller number of lines/chars (compared to Lisp).

Or see this Haskell function:
powerset = foldr (\x ys -> ys ++ (map (x:) ys)) [[]]

In Lisp we can do exactly the same one liner. Here it is (also in one
line, in some sense):
(defun powerset (set)
   (reduce (lambda (x ys)
             (append ys (mapcar (lambda (y)
                                  (cons x y))
                                ys)))
           set
           :initial-value '(())
           :from-end t))

Lisp does not offer a separate foldr and foldl. Reduce is doing both.
But in the case of a foldr we need to add  :from-ent t
Here is the same Haskell code, indented with Lisp style:
powerset set =
   foldr (\x ys ->
           ++ ys (map (\y
                        x:y)
                      ys))
         [[]]
         set

If Haskell also would use one function for foldr and foldl we also had
to add this line.
So, these two functions do exactly the same. Haskell uses more syntatic
sugar which cuts down the byte count.

When we take this in mind then the Lisp code that was presented took up
much less lines. Maybe around your OCaml solution. But it is very hard
to compare.
But it seems that your OCaml programs execute the task much faster.
Conceptually the Lisp programs don't have to be more complicated.

 From that perspective I think your statement that your implementation
is shorter is not correct.


Andr�
-- 
0
Reply address.good.until.2007.dec.26 (60) 7/22/2007 9:47:25 PM

Andr� Thieme schrieb:
> Counting lines makes not much sense for Lisp. Although it supports all
> these programming paradigms it has a very unique style which will blow
> up the LOC count in several cases. But from this it doesn't follow, that
> coding takes longer.
> 
> This one liner:  (defun make-accumulator (n) (lambda (i) (incf n i)))
> gets usually written in three visible lines:
> (defun make-accumulator (n)
>   (lambda (i)
>     (incf n i)))

There are two answers to that:

1. Coding doesn't take longer, but you can't place the same amount of 
code on a screenful, so debugging and maintenance will take longer.
Note that your typical generic FPL not only fits on a line, it even 
takes less of a line; the syntactic Haskell equivalent of the above 
example would look like this:
   make-accumulator N = incf N
(No, Haskell isn't cheating, it simply doesn't have or need macros and 
quoting, so it can encode the same code with far less symbols.)
Now that's 27 instead of 52 characters, which means I can put nearly 
double the code on a single line without cramming it.
(I'd expect OCaml to be slightly more verbose. Jon?)

2. You can always count nodes in the AST instead of lines of code. For 
the above example, you'd end up at roughly the same figures for Lisp and 
your generic FPL, but as soon as you declare macros in Lisp, the FPL 
needs less nodes.
(There may be other effects. Jon?)

Regards,
Jo
0
Reply jo427 (1164) 7/23/2007 8:07:48 AM

Joachim Durchholz <jo@durchholz.org> writes:

> (No, Haskell isn't cheating, it simply doesn't have or need macros and
> quoting, so it can encode the same code with far less symbols.)

Doesn't have?  Yes.  Doesn't need?  People who started Liskell or
Template Haskell would probably disagree.

Tamas
0
Reply tkpapp (975) 7/23/2007 8:19:28 AM

Hi,

> the syntactic Haskell equivalent of the above
> example would look like this:
>    make-accumulator N = incf N

Not really.

First of all, INCF is a macro.  How do you curry a macro?  That
doesn't make much sense to me.

Second, INCF takes a place as its first argument, not a value.

Third, INCF takes a variable number of arguments.  How is the compiler
supposed to know wheter MAKE-ACCUMULATOR is of type Number a => a -> a
or of type Number a => a?

So yes, claiming that the above pieces of code are syntactically
equivalent _is_ cheating (macros are part of the syntax, after all).
You may argue about the utility of macros, but that's beside the
point, for the fact is, Common Lisp _does_ have macros (and places,
and variable number argument lists, both of which I find extremely
useful), and they're not going away anytime soon.

Haskell has its advantages over Common Lisp, of course, but it's
certainly not a "better Lisp", and its syntax is not "better S-
expressions but without macros", as macros are part of the _point_ of
S-expressions.

Do you want to be able to express common idioms more concisely, or do
you want to have the power to create your own idioms in a straight-
forward way?  It's a trade-off.  I have yet to see a syntax that is
both as flexible as and more concise than that of Common Lisp.

Mata ne,
Matthias

0
Reply mulkiatsch (106) 7/23/2007 10:45:37 AM

Tamas Papp wrote:
> Doesn't have?  Yes.  Doesn't need?  People who started Liskell or
> Template Haskell would probably disagree.

Sure, but the vast majority of OCaml and Haskell coders who could use their
excellent macro systems choose not to.

I do not doubt that Lisp's macros are extremely useful for Lisp programmers
but I would contest any generalization that macros are necessary for
programming or that all languages should have macro systems, which is an
opinion often put forward on c.l.l.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/23/2007 12:04:11 PM

Matthias Benkard wrote:
> Do you want to be able to express common idioms more concisely, or do
> you want to have the power to create your own idioms in a straight-
> forward way?  It's a trade-off.  I have yet to see a syntax that is
> both as flexible as and more concise than that of Common Lisp.

Have a look at OCaml.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/23/2007 12:07:39 PM

On Jul 23, 10:07 am, Joachim Durchholz <j...@durchholz.org> wrote:
> Andr=E9 Thieme schrieb:
>
> > Counting lines makes not much sense for Lisp. Although it supports all
> > these programming paradigms it has a very unique style which will blow
> > up the LOC count in several cases. But from this it doesn't follow, that
> > coding takes longer.
>
> > This one liner:  (defun make-accumulator (n) (lambda (i) (incf n i)))
> > gets usually written in three visible lines:
> > (defun make-accumulator (n)
> >   (lambda (i)
> >     (incf n i)))
>
> There are two answers to that:
>
> 1. Coding doesn't take longer, but you can't place the same amount of
> code on a screenful, so debugging and maintenance will take longer.
> Note that your typical generic FPL not only fits on a line, it even
> takes less of a line; the syntactic Haskell equivalent of the above
> example would look like this:
>    make-accumulator N =3D incf N
> (No, Haskell isn't cheating, it simply doesn't have or need macros and
> quoting, so it can encode the same code with far less symbols.)
> Now that's 27 instead of 52 characters, which means I can put nearly
> double the code on a single line without cramming it.
> (I'd expect OCaml to be slightly more verbose. Jon?)
>
> 2. You can always count nodes in the AST instead of lines of code. For
> the above example, you'd end up at roughly the same figures for Lisp and
> your generic FPL, but as soon as you declare macros in Lisp, the FPL
> needs less nodes.
> (There may be other effects. Jon?)
>
> Regards,
> Jo

This turned into a pissing contest,  why doesn't this discussion going
solely on comp.lang.functional without crossposting so it will be seen
only by those people who care if language x *better* than language y
because it has a biggest , I mean smallest line count.


0
Reply slobodan.blazeski (1459) 7/23/2007 12:23:23 PM

Jon Harrop wrote:

> Have a look at OCaml.

Turns out that has got some seriously fugly syntax.


0
Reply david.golden (499) 7/23/2007 12:25:32 PM

Joachim Durchholz wrote:
> There are two answers to that:
> 
> 1. Coding doesn't take longer,

Even if there is four times as much code?

> but you can't place the same amount of 
> code on a screenful, so debugging and maintenance will take longer.

Yes. I would expect that to result in superlinear degredation of development
speed with respect to LOC.

> Note that your typical generic FPL not only fits on a line, it even
> takes less of a line; the syntactic Haskell equivalent of the above
> example would look like this:
>    make-accumulator N = incf N

A literal translation:

# (fun (+) n i -> n := !n + i);;
- : ('a -> 'b -> 'a) -> 'a ref -> 'b -> unit = <fun>

A useful translation to count the number of elements in a list:

# let length list = List.fold_left (fun n _ -> n+1) 0 list;;
val length : 'a list -> int = <fun>

To count the number of elements in any container:

# let length fold seq = fold (fun n _ -> n+1) 0 seq;;
val length : ((int -> 'a -> int) -> int -> 'b -> 'c) -> 'b -> 'c = <fun>

To sum the int elements in any container:

# let sum fold seq = fold (+) 0 seq;;
val sum : ((int -> int -> int) -> int -> 'a -> 'b) -> 'a -> 'b = <fun>

To sum elements of any type in any container:

# let sum add zero fold seq = fold add zero seq;;
val sum : 'a -> 'b -> ('a -> 'b -> 'c -> 'd) -> 'c -> 'd = <fun>

and so on. In practice, this code would never see the light of day because
real accumulators have too little in common to make such factoring useful.
For example, if you want to sum the elements of a floating point vector you
would take their magnitude into account to avoid unnecessary numerical
errors. If you want to "accumulate" strings (i.e. a StringBuilder) you
would amortize appends to reduce complexity from quadratic to linear.

> 2. You can always count nodes in the AST instead of lines of code.

Lisp's verbosity stems primarily from its use of whitespace and parentheses
as well as a lack of pattern matching. You can see this in almost any
comparable programs written in the two languages (or any languages with the
similar features, e.g. Haskell vs Scheme). Look at the intersect routines
from my ray tracer. First the Lisp:

(defun intersect (orig dir scene)
  (labels ((aux (lam normal scene)
             (let* ((center (sphere-center scene))
                    (lamt (ray-sphere orig
                                      dir
                                      center
                                      (sphere-radius scene))))
               (if (>= lamt lam)
                   (values lam normal)
                   (etypecase scene
                     (group
                      (dolist (kid (group-children scene))
                        (setf (values lam normal)
                              (aux lam normal kid)))
                      (values lam normal))
                     (sphere
                      (values lamt (unitise
                                    (-v (+v orig (*v lamt dir)) center)))))))))
    (aux infinity zero scene)))

Then the OCaml:

let rec intersect o d (l, _ as hit) (c, r, s) =
  let l' = ray_sphere o d c s in
  if l' >= l then hit else match s with
    [] -> l', unitise (o +| l' *| d -| c)
  | ss -> List.fold_left (intersect o d) hit ss

Look at the core interpreters in this Minim shootout. First the OCaml:

let rec test = function
  | `Comp(c, x, y) -> c !x !y
  | `And(f, g) -> test f && test g
  | `Or(f, g) -> test f || test g
  | `Not f -> not(test f)

let rec statement pc = function
  | `Assign(x, y) -> x := !y; pc + 1
  | `Incr x -> incr x; pc + 1
  | `Decr x -> decr x; pc + 1
  | `If(p, t, f) -> statement pc (if test p then t else f)
  | `Goto tag -> !tag
  | `PrintString s -> print_string s; pc + 1
  | `Print x -> print_int(!x); pc + 1
  | `Input x -> x := int_of_string(input_line stdin); pc + 1

let rec run program pc = run program (statement pc program.(pc))

Then the Qi:

(define run
   {program --> env}
    Program -> (run-loop Program Program []))

(define run-loop
   {program --> program --> env --> env}
    [] _ Env -> Env
    [nl | Ss] Program Env -> (do (output "~%") (run-loop Ss Program
Env))
    [Tag | Ss] Program Env -> (run-loop Ss Program Env) where (symbol?
Tag)
    [[goto Tag] | _] Program Env -> (run-loop (go Tag Program) Program
Env)
    [[Var is Val] | Ss] Program Env
    -> (run-loop Ss Program (change-env Var (compute-val Val Env)
Env))
    [[++ Var] | Ss] Program Env
    -> (run-loop Ss Program (change-env Var (+ 1 (look-up Var Env))
Env))
    [[-- Var] | Ss] Program Env
    -> (run-loop Ss Program (change-env Var (- (look-up Var Env) 1)
Env))
    [[if Test then DoThis else DoThat] | Ss] Program Env
     -> (if (perform-test? Test Env)
            (run-loop [DoThis | Ss] Program Env)
            (run-loop [DoThat | Ss] Program Env))
    [[print M] | Ss] Program Env -> (do (output "~A" (look-up M Env))
                                        (run-loop Ss Program Env))
                                                                               
where (symbol? M)
    [[print M] | Ss] Program Env -> (do (output "~A" M)
                                        (run-loop Ss Program Env))
    [[input Var] | Ss] Program Env
       -> (run-loop Ss Program (change-env Var (input+ : number)
Env)))

(define compute-val
  {val --> env --> number}
   N _ -> N     where (number? N)
   Var Env -> (look-up Var Env) where (symbol? Var))

(define go
  {symbol --> program --> program}
   Tag [Tag | Program] -> Program
   Tag [_ | Program] -> (go Tag Program)
   Tag _ -> (error "cannot go to tag ~A~%" Tag))

(define perform-test?
  {test --> env --> boolean}
   [Test1 and Test2] Env -> (and (perform-test? Test1 Env)
                                 (perform-test? Test2 Env))
   [Test1 or Test2] Env -> (or (perform-test? Test1 Env)
                               (perform-test? Test2 Env))
   [not Test] Env -> (not (perform-test? Test Env))
   [V1 = V2] Env -> (= (compute-val V1 Env) (compute-val V2 Env))
   [V1 > V2] Env -> (> (compute-val V1 Env) (compute-val V2 Env))
   [V1 < V2] Env -> (< (compute-val V1 Env) (compute-val V2 Env)))

(define change-env
   {symbol --> number --> env --> env}
    Var Val [] -> [(@p Var Val)]
    Var Val [(@p Var _) | Env] -> [(@p Var Val) | Env]
    Var Val [Binding | Env] -> [Binding | (change-env Var Val Env)])

(define look-up
  {symbol --> env --> number}
   Var [] -> (error "~A is unbound.~%" Var)
   Var [(@p Var Val) | _] -> Val
   Var [_ | Env] -> (look-up Var Env))

> For 
> the above example, you'd end up at roughly the same figures for Lisp and
> your generic FPL, but as soon as you declare macros in Lisp, the FPL
> needs less nodes.

Are you saying that macros reduce code size?

> (There may be other effects. Jon?)

Pattern matching is the single biggest advantage and is the main reason why
OCaml, SML, Haskell and F# are all much more concise than Common Lisp. Look
at the amount of code doing destructing in the above examples.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/23/2007 12:46:51 PM

> I do not doubt that Lisp's macros are extremely useful for Lisp programmers
> but I would contest any generalization that macros are necessary for
> programming or that all languages should have macro systems, which is an
> opinion often put forward on c.l.l.

ACK.

Regards -- Markus

0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/23/2007 1:51:42 PM

Pascal Costanza wrote:
> Jon Harrop wrote:
>> Pascal Costanza wrote:
>>> ...and why would that matter?!?
>>
>> Indeed.
>>
>>> [The following should be quite fast - but I haven't performed any test
>>> runs. I am interested in your results, though. It should be possible to
>>> squeeze out more by adding declarations...]
>>
>> By my measurements, this is 2-3x longer and twice as fast as the fastest
>> OCaml interpreter. By the looks of the code it is using a macro to
>> translate to Lisp and then compiling, in which case I am surprised the
>> performance is not better. I assume it is doing a very simple translation
>> to rather inefficient Lisp?
> 
> Yes. As I said, there are no type declarations in the generated code. It 
> should be straightforward to declare all variables as integers, but then 
> all incoming values from (input var) forms have to be type checked. 

Here is a new version to try out. Note that I declared the variables as 
fixnum, which means that they wrap around beyond a certain threshold. 
That number is implementation-dependent and is stored in the constant 
MOST-POSITIVE-FIXNUM. For example, in SBCL it's 536870911. If that's too 
small for your tests, change the *variable-type* parameter to 'integer 
and recompile. (In Common Lisp, integer is unlimited for correctness.) 
It's also fun to call (disassemble 'test-minim) after compilation (with 
any type).

I have also fixed the bug in the interpreter which I reported on before.

As an additional note: The code is roughly 2x longer than necessary 
because of the optimization added via the compiler macro. In a more 
realistic scenario, you would use the interpreter only, and only 
optimize the code as soon as you notice that there is a performance 
bottleneck here. In an even more realistic scenario, you would probably 
use a pure macro version from the start, but Mark wanted an interpreter, 
so there you go.


Cheers,
Pascal


(defvar *tag-table* '())
(defvar *var-table* '())
(defvar *program*)

;;
;; change this parameter for different variable types
;;
(eval-when (:compile-toplevel :load-toplevel :execute)
   (defparameter *variable-type* 'fixnum))


(defun eval-statements (statement more-statements)
   (flet ((cont () (when more-statements
                     (eval-statements
                       (car more-statements)
                       (cdr more-statements)))))
     (etypecase statement
       (symbol (if (eq statement 'nl)
                 (terpri)
                 (setf (getf *tag-table* statement)
                       (cons statement more-statements)))
               (cont))
       (cons (case (car statement)
               (if (destructuring-bind
                       (<if> test <then> then <else> else) statement
                     (declare (ignore <if>))
                     (assert (and (eq <then> 'then) (eq <else> 'else)))
                     (if (eval-test test)
                       (eval-statements then more-statements)
                       (eval-statements else more-statements))))
               (goto (destructuring-bind
                         (<goto> tag) statement
                       (declare (ignore <goto>))
                       (let ((continuation (or (getf *tag-table* tag)
                                               (member tag *program*))))
                         (eval-statements
                           (car continuation)
                           (cdr continuation)))))
               (print (destructuring-bind
                          (<print> value) statement
                        (declare (ignore <print>))
                        (princ (eval-value value))
                        (finish-output)
                        (cont)))
               (input (destructuring-bind
                          (<input> var) statement
                        (declare (ignore <input>))
                        (assert (symbolp var))
                        (setf (getf *var-table* var) (read))
                        (cont)))
               (++ (destructuring-bind
                       (<++> var) statement
                     (declare (ignore <++>))
                     (assert (symbolp var))
                     (incf (getf *var-table* var))
                     (cont)))
               (-- (destructuring-bind
                       (<--> var) statement
                     (declare (ignore <-->))
                     (assert (symbolp var))
                     (decf (getf *var-table* var))
                     (cont)))
               (otherwise (destructuring-bind
                              (var1 <is> var2) statement
                            (assert (and (symbolp var1)
                                         (eq <is> 'is)
                                         (symbolp var2)))
                            (setf (getf *var-table* var1)
                                  (getf *var-table* var2))
                            (cont))))))))

(defun eval-value (value)
   (typecase value
     (symbol (getf *var-table* value))
     (otherwise (assert (atom value)) value)))

(defun eval-test (test)
   (if (eq (car test) 'not)
     (destructuring-bind (<not> test) test
       (declare (ignore <not>))
       (not (eval-test test)))
     (destructuring-bind (arg1 op arg2) test
       (ecase op
         (> (> (eval-value arg1) (eval-value arg2)))
         (< (< (eval-value arg1) (eval-value arg2)))
         (= (= (eval-value arg1) (eval-value arg2)))
         (and (and (eval-test arg1) (eval-test arg2)))
         (or (or (eval-test arg1) (eval-test arg2)))))))

(defun eval-minim (statements)
   (let ((*program* statements))
     (eval-statements (car statements) (cdr statements))))

(define-compiler-macro eval-minim (&whole whole statements)
   (unless (and (consp statements) (eq (car statements) 'quote))
     (return-from eval-minim whole))
   (let ((variables '()))
     (labels ((translate-statement (statement)
                (etypecase statement
                  (symbol (if (eq statement 'nl) '(terpri) statement))
                  (cons (case (car statement)
                          (if (destructuring-bind
                                  (<if> test <then> then <else> else)
                                  statement
                                (declare (ignore <if>))
                                (assert (and (eq <then> 'then)
                                             (eq <else> 'else)))
                                `(if ,(translate-test test)
                                   ,(translate-statement then)
                                   ,(translate-statement else))))
                          (goto (destructuring-bind
                                    (<goto> tag) statement
                                  (declare (ignore <goto>))
                                  `(go ,tag)))
                          (print (destructuring-bind
                                     (<print> value) statement
                                   (declare (ignore <print>))
                                   `(progn
                                      (princ ,(translate-value value))
                                      (finish-output))))
                          (input (destructuring-bind
                                     (<input> var) statement
                                   (declare (ignore <input>))
                                   (assert (symbolp var))
                                   (pushnew var variables)
                                   (let ((input (gensym)))
                                     `(let ((,input (read)))
                                        (check-type
                                          ,input ,*variable-type*)
                                        (setq ,var ,input)))))
                          (++ (destructuring-bind
                                  (<++> var) statement
                                (declare (ignore <++>))
                                (assert (symbolp var))
                                (pushnew var variables)
                                `(incf ,var)))
                          (-- (destructuring-bind
                                  (<--> var) statement
                                (declare (ignore <-->))
                                (assert (symbolp var))
                                (pushnew var variables)
                                `(decf ,var)))
                          (otherwise (destructuring-bind
                                         (var1 <is> var2) statement
                                       (assert (and (symbolp var1)
                                                    (eq <is> 'is)
                                                    (symbolp var2)))
                                       (pushnew var1 variables)
                                       (pushnew var2 variables)
                                       `(setq ,var1 ,var2)))))))
              (translate-test (test)
                (if (eq (car test) 'not)
                  (destructuring-bind (<not> test) test
                    (declare (ignore <not>))
                    `(not ,(translate-test test)))
                  (destructuring-bind (arg1 op arg2) test
                    (ecase op
                      ((> < =) `(,op ,(translate-value arg1)
                                     ,(translate-value arg2)))
                      ((and or) `(,op ,(translate-test arg1)
                                      ,(translate-test arg2)))))))
              (translate-value (value)
                (when (symbolp value) (pushnew value variables))
                (assert (atom value)) value))
       (let ((new-statements
               (mapcar #'translate-statement (cadr statements))))
         `(prog ,(loop for var in variables collect `(,var 0))
            (declare (optimize (speed 3) (safety 0) (debug 0)
                               (compilation-speed 0))
                     (,*variable-type* ,@variables))
            ,@new-statements)))))

(defun test-minim ()
   (eval-minim
    '((print "Add x and y")
      nl
      (print "Input x: ")
      (input x)
      nl
      (print "Input y: ")
      (input y)
      nl
      main
      (if (x = 0) then (goto end) else (goto sub1x))

      sub1x
      (-- x)
      (++ y)
      (goto main)

      end
      nl
      (print "The total of x and y is ")
      (print y)
      nl)))

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/23/2007 1:53:30 PM

Jon Harrop wrote:

> Lisp's verbosity stems primarily from its use of whitespace and
> parentheses as well as a lack of pattern matching.

Of course, if a lisp coder really wants pattern matching, they just
load a pattern matcher / unifier.

Actually, much of the shortening is coming from simply using
shorter or single-character identifiers in your ML code where Lisp (or
apparently Qi) authors would use more meaningful ones - hardly a
sensible comparison.  One can write Qi or Lisp with single-character
identifiers. It's just not considered particularly good style.

I can rewrite a pattern match from Mark's Qi into something a little
more like your ML in style:

 [[if Test then DoThis else DoThat] | Ss] Program Env
     -> (if (perform-test? Test Env)
            (run-loop [DoThis | Ss] Program Env)
            (run-loop [DoThat | Ss] Program Env))

===>

[[if X then A else B] | Ss] P E -> 
        (if (pt X E) (rl [A | Ss] P E) (rl [B | Ss] P E))


Oh look, I've "halved" the length (if you're measuring LOC, which is a
ridiculous measure anyway for most languages, not just lisp or ML). Of
course it's also got less readable, like your (but not all) ML.






0
Reply david.golden (499) 7/23/2007 2:23:57 PM

David Golden <david.golden@oceanfree.net> wrote:
> Oh look, I've "halved" the length (if you're measuring LOC, which is a
> ridiculous measure anyway for most languages, not just lisp or ML). Of
> course it's also got less readable, like your (but not all) ML.

It's been pointed out before I'm sure, but perhaps a better way to
compare syntactic program complexity is to measure the number of lexer
tokens. (Assuming the lexer spits out a single token for things like
identifiers of course).

There is of course no obviously correct way to do this in any case.

Phil

-- 
http://www.kantaka.co.uk/ .oOo. public key: http://www.kantaka.co.uk/gpg.txt
0
Reply phil-news (48) 7/23/2007 3:42:49 PM

David Golden wrote:
> Jon Harrop wrote:
>> Lisp's verbosity stems primarily from its use of whitespace and
>> parentheses as well as a lack of pattern matching.
> 
> Of course, if a lisp coder really wants pattern matching, they just
> load a pattern matcher / unifier.

Greenspun. If you put a couple of years into it you'll be where Mark is now
with Qi. If you work really hard for another 30 years you might get to
where OCaml, Haskell or F# are now.

> Actually, much of the shortening is coming from simply using
> shorter or single-character identifiers in your ML code where Lisp (or
> apparently Qi) authors would use more meaningful ones - hardly a
> sensible comparison.

On the contrary, when trying to compare brevity I see no merit in ignoring
verbosity.

> One can write Qi or Lisp with single-character 
> identifiers. It's just not considered particularly good style. 

It also makes little difference (see below).

> I can rewrite a pattern match from Mark's Qi into something a little
> more like your ML in style:
> 
>  [[if Test then DoThis else DoThat] | Ss] Program Env
>      -> (if (perform-test? Test Env)
>             (run-loop [DoThis | Ss] Program Env)
>             (run-loop [DoThat | Ss] Program Env))
> 
> ===>
> 
> [[if X then A else B] | Ss] P E ->
>         (if (pt X E) (rl [A | Ss] P E) (rl [B | Ss] P E))
> 
> Oh look, I've "halved" the length (if you're measuring LOC, which is a
> ridiculous measure anyway for most languages, not just lisp or ML). Of
> course it's also got less readable, like your (but not all) ML.

To be fair, I am sure you will want to take the OCaml:

  `If(p, t, f) -> statement pc (if test p then t else f)

and perform equivalent compression:

  `If(p, f, g) -> s n (if t p then f else g)

As you can see, the compressed OCaml is significantly shorter than the
compressed Qi. The only useful conclusion we can draw from this is that the
length of identifiers was not, in fact, relevant.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/23/2007 3:49:24 PM

Jon Harrop wrote:

>> Of course, if a lisp coder really wants pattern matching, they just
>> load a pattern matcher / unifier.
> 
> Greenspun.

Yeah, just like it's greenspunning yacc how you used the parser module
for ocaml. Very, very lame, Jonnie boy.

> As you can see, the compressed OCaml is significantly shorter than the
> compressed Qi.

That rather missed the point of the example (which was stylistic
contrast, illustrating that indeed, using short identifiers makes code
look shorter). 

You conflate another issue: your ML "if" match line is not doing the
same thing as Mark's Qi "if" match line (hint: when/if you work out why
it's not, you'll also work out why it's both unsurprising and
uninteresting your ML was faster than Mark's Qi interpreter).


0
Reply david.golden (499) 7/23/2007 4:25:55 PM

Jon Harrop <jon@ffconsultancy.com> wrote:
>
>Lisp's verbosity stems primarily from its use of whitespace and parentheses
>as well as a lack of pattern matching. You can see this in almost any
>comparable programs written in the two languages (or any languages with the
>similar features, e.g. Haskell vs Scheme). Look at the intersect routines
>from my ray tracer.

I think the comparison would be fairer if you used the same variable names
in each language. You've used words in the Lisp and single letters in the
O'Caml, which undermines your argument. You have also wasted vertical
space in the Lisp, and maximized vertical compression in the O'Caml,
in both cases more than I would say is normal.

Tony.
-- 
f.a.n.finch  <dot@dotat.at>  http://dotat.at/
PORTLAND PLYMOUTH: NORTHWESTERLY BACKING SOUTHWESTERLY 4 OR 5, INCREASING 6 OR
7 FOR A TIME. SLIGHT OR MODERATE, OCCASIONALLY ROUGH. RAIN OR THUNDERY
SHOWERS. MODERATE OR GOOD.
0
Reply dot1 (27) 7/23/2007 5:37:17 PM

Jon Harrop wrote:
> Tamas Papp wrote:
>> Doesn't have?  Yes.  Doesn't need?  People who started Liskell or
>> Template Haskell would probably disagree.
> 
> Sure, but the vast majority of OCaml and Haskell coders who could use their
> excellent macro systems choose not to.
> 
> I do not doubt that Lisp's macros are extremely useful for Lisp programmers
> but I would contest any generalization that macros are necessary for
> programming or that all languages should have macro systems, which is an
> opinion often put forward on c.l.l.

....or you just misunderstand them.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/23/2007 6:02:39 PM

Phil Armstrong wrote:
> David Golden <david.golden@oceanfree.net> wrote:
>> Oh look, I've "halved" the length (if you're measuring LOC, which is a
>> ridiculous measure anyway for most languages, not just lisp or ML). Of
>> course it's also got less readable, like your (but not all) ML.
> 
> It's been pointed out before I'm sure, but perhaps a better way to
> compare syntactic program complexity is to measure the number of lexer
> tokens. (Assuming the lexer spits out a single token for things like
> identifiers of course).
> 
> There is of course no obviously correct way to do this in any case.

Although that works well for Lisp or Scheme, lexical tokens have no
correspondence to perceived verbosity when the grammar is complicated
though. For example, I couldn't tell you what the tokens are here:

# let foo ?(t=[]) h = h::t;;
val foo : ?t:'a list -> 'a -> 'a list = <fun>

Is [] a single token, or is it two? Is [] twice as verbose as NIL?

  multiple-value-bind

is five times more verbose in OCaml than Lisp:

  multiple - value - bind

etc.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/23/2007 6:47:19 PM

>>>>> "Jon" == Jon Harrop <jon@ffconsultancy.com> writes:

  Jon> Joachim Durchholz wrote:
  >>  There are two answers to that:
  >>
  >> 1. Coding doesn't take longer,

  Jon> Even if there is four times as much code?

  >>  but you can't place the same amount of code on a screenful, so
  >>  debugging and maintenance will take longer.

  Jon> Yes. I would expect that to result in superlinear degredation
  Jon> of development speed with respect to LOC.

I've been quoted as stating that development speed in terms
of lines of code per man-hour* seems to be the same regardless
of language, and that LOC reduction should result in roughly
linear improvement in development speed. We've noted that the
same seems to be true for fault density**, with corresponding 
effects on product quality. This would seem to support your
assumption about a superlinear difference overall 

*  Development + testing up until product release
** Faults found in the field, measured in faults/KLOC

I think a long-term effect of relieving the programmer
of concern for low-level memory management, locking,
etc. will eventually allow programmers to adjust their
frame of mind and ways of working (e.g. smaller projects,
less bureaucracy, perhaps fewer and better programmers***),
will give additional factors of productivity improvement,
but this is mainly speculation, which BTW would seem to 
invalidate my initial assumption, but support yours. ;-)

*** While one should really have top-notch programmers to
    get away with C++ programming in the large, the need 
    for large projects tends to drive away the best 
    programmers.

BR,
Ulf W
-- 
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Team Leader, Software Characteristics
 / / /     Ericsson AB, IMS Gateways
0
Reply etxuwig (64) 7/23/2007 7:39:51 PM

David Golden wrote:
> You conflate another issue: your ML "if" match line is not doing the
> same thing as Mark's Qi "if" match line (hint: when/if you work out why
> it's not, you'll also work out why it's both unsurprising and
> uninteresting your ML was faster than Mark's Qi interpreter).

Sounds like another triumph of hope over reality.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/23/2007 8:07:32 PM

Jon Harrop escreveu:
> Joachim Durchholz wrote:
[snipped]
>> For 
>> the above example, you'd end up at roughly the same figures for Lisp and
>> your generic FPL, but as soon as you declare macros in Lisp, the FPL
>> needs less nodes.
> 
> Are you saying that macros reduce code size?
> 
>> (There may be other effects. Jon?)
> 
> Pattern matching is the single biggest advantage and is the main reason why
> OCaml, SML, Haskell and F# are all much more concise than Common Lisp. Look
> at the amount of code doing destructing in the above examples.
> 

Humm... I still find your comparison loaded: you rule out the use of 
libraries for pattern matching in Lisp. Why?
0
Reply csrabak (393) 7/23/2007 10:00:30 PM

Cesar Rabak wrote:
> Jon Harrop escreveu:
>> Pattern matching is the single biggest advantage and is the main 
>> reason why OCaml, SML, Haskell and F# are all much more concise 
>> than Common Lisp. 
> Humm... I still find your comparison loaded: you rule out the use of 
> libraries for pattern matching in Lisp. Why?

Because it sells books.

-- 
Dan
www.prairienet.org/~dsb/
0
Reply randomgeek (299) 7/23/2007 10:12:54 PM

Mark Tarver <dr.mtarver@ukonline.co.uk> writes:
>Here's the stock program to add two numbers together in Minim -
>designed to here run under Qi. You should be able to follow it.

  Here is a Java implementation. It does not follow the formal
  type semantics precisely and just runs the example program -
  not the rest of the language. Both could be added keeping the
  global structure of the code.

  It uses the library "ram.jar"

http://www.purl.org/stefan_ram/pub/ram-jar

  to read the program to a kind of S-expression. Because "=" has
  a special meaning for this kind of S-expression, "=" was
  renamed to "eq". The source also was slightly reformatted to
  use other delimiters for lists and strings.

  A preprocessor converts texts in single quotes as used below
  to Java identifiers.

  The main parts of the program:

    method main              iterate through the program
    method execute           execute a statement
    method value             evaluate an expression
    object of class Input    the input from the user
    object of class State    the state of the interpreter
    objects of class Symbol  a statement or an expression
                             .of(kw)     does it have keyword kw?
                             .operand(i) operand #i of the keyword
                             .string(i)  operand #i as a string
                             .room(i)    operand #i as a list

import de.dclj.ram.notation.unotal.RoomSource;
import static de.dclj.ram.notation.unotal.RoomFromModule.roomFrom;
import static java.lang.System.out;

public class Main
{ public static void main( final java.lang.String[] args )
  { final Input input = new Input();
    final State state = new State( input );
    boolean running = true; while( running )
    { final java.lang.Object 'source entry' = state.'current entry'();
      if( 'source entry' instanceof RoomSource )
      { final Symbol statement = new Symbol( 'source entry' );
        running = running && execute( statement, state ); }
      ++state.'source pos'; 
      if( state.empty() )running = false; }}

  static boolean execute( final Symbol statement, final State state )
  { boolean running = true; if( statement.of( "end" ))
    { running = false; }
    else if( statement.of( "print" ))
    { java.lang.System.out.println
      ( state.value.containsKey( statement.string( 0 ))? 
        value( statement.string( 0 ), state ) : statement.string( 0 )); }
    else if( statement.of( "input" ))
    { state.value.put
      ( statement.string( 0 ), state.input.data.get( state.'input pos'++ )); }
    else if( statement.of( "if" ))
    { execute
      ( new Symbol
        ( statement.room( value( statement.room( 0 ), state ) == 0 ? 4 : 2 )), 
        state ); }
    else if( statement.of( "goto" ))
    { state.'go to'( statement.string( 0 )); }
    else if( statement.of( "--" ))
    { state.value.put
      ( statement.string( 0 ), 
        java.lang.String.valueOf
        ( value( statement.string( 0 ), state ) - 1 )); }
    else if( statement.of( "++" ))
    { state.value.put
      ( statement.string( 0 ), 
        java.lang.String.valueOf
        ( value( statement.string( 0 ), state ) + 1 )); }
    return running; }

  static int value( final java.lang.Object object, final State state )
  { int result = java.lang.Integer.MIN_VALUE;
    if( object instanceof java.lang.String )
    { final java.lang.String string =( java.lang.String )object;
      if( string.matches( "[0-9]+" ))
      { result = java.lang.Integer.valueOf( string ); }
      else
      { result = java.lang.Integer.valueOf
        (( java.lang.String )state.value.get( string )); }}
    else
    { final Symbol expression = new Symbol( object );
      if( expression.of( "eq" ))
      { final int l = value( expression.operand( 0 ), state );
        final int r = value( expression.operand( 1 ), state ); 
        result = l == r ? -1 : 0; }}
    return result; }}

class Input
{ final RoomSource source = roomFrom
  ( "                                                                     " +
    "                                                                     " +
    "                                                                     " +
    "       < < print [Add x and y] >                                     " +
    "                                                                     " +
    "         < print [Input x: ] >                                       " +
    "         < input x >                                                 " +
    "                                                                     " +
    "         < print [Input y: ] >                                       " +
    "         < input y >                                                 " +
    "                                                                     " +
    "         main                                                        " +
    "         < if< x eq 0 >then< goto end >else< goto sub1x >>           " +
    "                                                                     " +
    "         sub1x                                                       " +
    "         < -- x >                                                    " +
    "         < ++ y >                                                    " +
    "         < goto main >                                               " +
    "                                                                     " +
    "         end                                                         " +
    "         < print [The total of x and y is ] >                        " +
    "         < print y >                                                 " +
    "                                                                     " +
    "         >                                                           " +
    "                                                                     " +
    "                                                                     " +
    "                                                                     " );
  final RoomSource data = roomFrom
  ( "< 10 20 >" ); }

class State
{ public final Input input;
  public State( final Input input )
  { this.input = input; }
  public final java.util.Map<java.lang.String,java.lang.Object> value =
  new java.util.HashMap<java.lang.String,java.lang.Object>();
  int 'source pos' = 0; 
  int 'input pos' = 0;
  public void 'go to'( final java.lang.String label )
  { for( int i = 0; i < input.source.length(); ++i )
    if( label.equals( this.input.source.get( i )))this.'source pos' = i; }
  public java.lang.Object 'current entry'()
  { return this.input.source.get( this.'source pos' ); }
  public boolean empty()
  { return this.'source pos' >= this.input.source.length(); }}

class Symbol
{ java.lang.String keyword = null;
  int 'keyword pos' = -1;
  RoomSource source = null;
  public Symbol( final java.lang.Object entry )
  { source =( RoomSource )entry;
    keywordPos = 0; 
    keyword =( java.lang.String )source.get( 0 );
    if( source.length() > 1 && 
      source.get( 1 )instanceof java.lang.String )
    { final java.lang.String cadr =( java.lang.String )source.get( 1 );
      if( "and".equals( cadr ) || "or".equals( cadr ) || "is".equals( cadr ) ||
        "<".equals( cadr ) || ">".equals( cadr ) || "eq".equals( cadr ))
      { 'keyword pos' = 1; keyword = cadr; }}}
  public final java.lang.String keyword(){ return this.keyword; }
  public final boolean of( final java.lang.String string )
  { return string.equals( this.keyword() ); }
  public final java.lang.Object operand( int pos )
  { if( pos >= 'keyword pos' )++pos;
    return this.source.get( pos ); }
  public final java.lang.String string( final int pos )
  { return( java.lang.String )this.operand( pos ); }
  public final RoomSource room( final int pos )
  { return( RoomSource )this.operand( pos ); }
  public final java.lang.String toString()
  { return this.source.toString(); }}

/*

Add x and y
Input x:
Input y:
The total of x and y is
30

*/

0
Reply ram (2828) 7/23/2007 10:34:18 PM

Joachim Durchholz schrieb:
> Andr� Thieme schrieb:
>> Counting lines makes not much sense for Lisp. Although it supports all
>> these programming paradigms it has a very unique style which will blow
>> up the LOC count in several cases. But from this it doesn't follow, that
>> coding takes longer.
>>
>> This one liner:  (defun make-accumulator (n) (lambda (i) (incf n i)))
>> gets usually written in three visible lines:
>> (defun make-accumulator (n)
>>   (lambda (i)
>>     (incf n i)))
> 
> There are two answers to that:
> 
> 1. Coding doesn't take longer, but you can't place the same amount of 
> code on a screenful, so debugging and maintenance will take longer.

This might be true for several cases.
I also see the scenario in mind where longer names for variables or
functions bring in advantages for readability.
However, if you wanted then you could compress code in Lisp as well.
For example with my DEF:
(def make-accumulator (n) [incf n])


> Note that your typical generic FPL not only fits on a line, it even 
> takes less of a line; the syntactic Haskell equivalent of the above 
> example would look like this:

Well, for some situations you are right, for others you are not.
It depends on what you want to do.
I gave the example about calculating the powerset.
One other Haskell solution is for example this one:
powerset = filterM (const [True, False])

To do the same in Lisp you first need to write like 40 LOC preparation
code.

In other situations Lisp can be the better option.
Joel Raymond wrote about Erlangs advantages over Haskell:
http://wagerlabs.com/2006/1/1/haskell-vs-erlang-reloaded/
For example point 3.2 was talking about static typing and the extra
code it needed.


>   make-accumulator N = incf N

Hmm, does Haskell have infc?
Is that some monad that can do the destructive manipulation on N?
What is the minus (between "make" and "accumulator") doing when it is
placed on the right side of a "="?


> (No, Haskell isn't cheating, it simply doesn't have or need macros and 
> quoting, so it can encode the same code with far less symbols.)

It is true that the need for Macros in Haskell is reduced. This comes
from implicit currying but mainly from lazyness.
In Lisp you could do the same. You could teach Lisp implicit currying
and also implicit lazyness (altough I think that it would feel really
bad).
So yes, several things that are expressed in Lisp with Macros would be
expressed without them in Haskell. However, I am not sure if that comes
without performance hits.


> Now that's 27 instead of 52 characters, which means I can put nearly 
> double the code on a single line without cramming it.

With short code examples it will probably often happen.



> 2. You can always count nodes in the AST instead of lines of code. For 
> the above example, you'd end up at roughly the same figures for Lisp and 
> your generic FPL, but as soon as you declare macros in Lisp, the FPL 
> needs less nodes.

This might be a little misunderstanding.
Usually after introducing macros the count of nodes is reduced.


Andr�
-- 
0
Reply address.good.until.2007.dec.26 (60) 7/23/2007 11:26:39 PM

Jonnie wrote:
> Sounds like another triumph of hope over reality

I don't think anyone's gonna buy that, Jonnie boy.
The Qi and ML programs as a whole may have similar
effects, but hey, I could drive or skate to
the shops too. 

 













0
Reply david.golden (499) 7/23/2007 11:31:24 PM

Dan Bensen escreveu:
> Cesar Rabak wrote:
>> Jon Harrop escreveu:
>>> Pattern matching is the single biggest advantage and is the main 
>>> reason why OCaml, SML, Haskell and F# are all much more concise than 
>>> Common Lisp. 
>> Humm... I still find your comparison loaded: you rule out the use of 
>> libraries for pattern matching in Lisp. Why?
> 
> Because it sells books.
> 
I see. . .
0
Reply csrabak (393) 7/24/2007 12:41:24 AM

ram@zedat.fu-berlin.de (Stefan Ram) writes:
>/*
>
>Add x and y
>Input x:
>Input y:
>The total of x and y is
>30
>
>*/

  So, this is supposed to be a benchmark for the execution time?

  The programm initially took about 15 or 25 seconds for 100000
  iterations.

  I did not write it with performance in mind. So I tried to do
  some microoptimizations for the name-value-lookup, integer
  variable storage and the label-offset-lookup and eventuelly it
  took just below 10 s:

Add x and y
Input x:
Input y:
The total of x and y is
200000

9,639743

  But this is running on historic hardware that was at the
  low end even when it was built about 10 years ago. It should
  run in about 1 s on a consumer class computer bought today.

  I believe that I now could write a faster interpreter by
  first translating the S-expression to an object model.

0
Reply ram (2828) 7/24/2007 12:56:43 AM

Matthias Benkard <mulkiatsch@gmail.com> writes:
> First of all, INCF is a macro.  How do you curry a macro?  That
> doesn't make much sense to me.

incf is a macro because macros are the only way to make Lisp forms
that don't evaluate their args.  Haskell uses lazy evaluation and
therefore all kinds of things that Lisp uses macros for, are done in
Haskell as ordinary functions.  Of course incf mutates its argument,
which normally isn't done in Haskell.  So you'd only code something
like incf as a monad action.
> 
> Third, INCF takes a variable number of arguments.  How is the compiler
> supposed to know wheter MAKE-ACCUMULATOR is of type Number a => a -> a
> or of type Number a => a?

Type inference.
0
Reply phr.cx (5483) 7/24/2007 1:11:15 AM

Ulf Wiger <etxuwig@cbe.ericsson.se> writes:
> I've been quoted as stating that development speed in terms
> of lines of code per man-hour* seems to be the same regardless
> of language, and that LOC reduction should result in roughly
> linear improvement in development speed. 

I wonder about this.  My hat off to anyone who can code in Haskell as
fast in LOC/hour as they can code in Java.  Of course the Java LOC
only do 1/10th as much, so coding 2x slower still leaves one ahead by
a factor of 5.
0
Reply phr.cx (5483) 7/24/2007 1:13:16 AM

>>>>> "Paul" == Paul Rubin <http://phr.cx@NOSPAM.invalid> writes:

  Paul> Ulf Wiger <etxuwig@cbe.ericsson.se> writes:
  >>  I've been quoted as stating that development speed in terms of
  >>  lines of code per man-hour* seems to be the same regardless of
  >>  language, and that LOC reduction should result in roughly linear
  >>  improvement in development speed.

  Paul> I wonder about this.  My hat off to anyone who can code in
  Paul> Haskell as fast in LOC/hour as they can code in Java.  Of
  Paul> course the Java LOC only do 1/10th as much, so coding 2x
  Paul> slower still leaves one ahead by a factor of 5.

I believe this is basically the point. For a sufficiently 
difficult problem, understanding how to build the program
takes much longer than writing it down. The speed of actually 
writing the code will depend on the ratio of trivial vs tricky
code. When trying to understand what you wrote, the code that is 
secondary to solving the actual problem will get in your way and
slow you down.

Our frame of reference was very large projects, where the actual
writing of code is a fairly small part of the overall project
time. And it's just a superficial observation, from comparing
actual metrics from several projects using different technologies.
It's only a little bit more solid than "a watched pot never boils."

The observation itself is not particularly novel. Brooks reported
someone as drawing the same conclusion in The Mythical Man-Month
(I don't have a copy of the book, so I can't check the reference).
We checked the numbers for a few of our projects and observed that
they seemed to corroborate Brooks' old rule of thumb, QED. (:


BR,
Ulf W
-- 
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Team Leader, Software Characteristics
 / / /     Ericsson AB, IMS Gateways
0
Reply etxuwig (64) 7/24/2007 6:03:08 AM

>>>>> Andre Thieme writes:

  Andre> In other situations Lisp can be the better option.  Joel
  Andre> Raymond wrote about Erlangs advantages over Haskell:
  Andre> http://wagerlabs.com/2006/1/1/haskell-vs-erlang-reloaded/ For
  Andre> example point 3.2 was talking about static typing and the
  Andre> extra code it needed.

A paper at the upcoming ICFP conference will present a more 
systematic comparison between C++, Erlang and Haskell.
It shows some interesting stuff, but also warns against too
far-reaching conclusions.

Evaluating High-Level Distributed Language Constructs
    by Jan Nystrom, Phil Trinder, David King

BR,
Ulf W
-- 
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Team Leader, Software Characteristics
 / / /     Ericsson AB, IMS Gateways
0
Reply etxuwig (64) 7/24/2007 6:15:03 AM

Andr� Thieme wrote:
> In other situations Lisp can be the better option.
> Joel Raymond wrote about Erlangs advantages over Haskell:
> http://wagerlabs.com/2006/1/1/haskell-vs-erlang-reloaded/
> For example point 3.2 was talking about static typing and the extra
> code it needed.

Look at the vector record and zero vector definition from my ray tracer. In
Lisp:

(defstruct (vec (:conc-name nil)
                (:constructor vec (x y z))
                (:type (vector double-float)))
  x y z)

(defvar zero (vec 0d0 0d0 0d0))

In OCaml:

type vec = {x:float; y:float; z:float}
let zero = {x=0.; y=0.; z=0.}

>> (No, Haskell isn't cheating, it simply doesn't have or need macros and
>> quoting, so it can encode the same code with far less symbols.)
> 
> It is true that the need for Macros in Haskell is reduced. This comes
> from implicit currying but mainly from lazyness.
> In Lisp you could do the same. You could teach Lisp implicit currying
> and also implicit lazyness (altough I think that it would feel really
> bad).

Greenspun.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 7:41:29 AM

David Golden wrote:
> Jonnie wrote:
>> Sounds like another triumph of hope over reality
> 
> I don't think anyone's gonna buy that, Jonnie boy.
> The Qi and ML programs as a whole may have similar
> effects, but hey, I could drive or skate to
> the shops too.

So you're saying that the comparison is grossly unfair in some unspecified
way. I don't suppose you could be more specific?

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 8:16:09 AM

Andr� Thieme <address.good.until.2007.dec.26@justmail.de> writes:
> In Lisp you could do the same. You could teach Lisp implicit currying
> and also implicit lazyness (altough I think that it would feel really bad).

You can't do anything of the sort.  Consider that Haskell has no
language support for exceptions or continuations, because they're
implemented straightforwardly as library modules, using a combination
of lazy evaluation and currying.  They can't be implemented that way
in Lisp, so exceptions are built into the language and continuations
(in CL) can't be done at all without nonstandard extensions.
0
Reply phr.cx (5483) 7/24/2007 9:06:50 AM

Stefan Ram wrote:
>   So, this is supposed to be a benchmark for the execution time?

Yes. I get a lot of errors when I try to compile it:

$ javac stefanram.java
stefanram.java:10: unclosed character literal
    { final java.lang.Object 'source entry' = state.'current entry'();
                             ^
stefanram.java:10: unclosed character literal
    { final java.lang.Object 'source entry' = state.'current entry'();

Any ideas what these mean?

>   I believe that I now could write a faster interpreter by
>   first translating the S-expression to an object model.

Java has lex and yacc tools (JavaCC combines these, IIRC) so you could use
them for parsing.

Define an abstract syntax tree (AST) as a class hierarchy with an abstract
base class representing the AST type. This will be more verbose than the
Lisp or OCaml because you have to write the classes down by hand in Java.
Get the parser to generate an AST.

When it comes to evaluation, you can use the built-in virtual function
dispatch (e.g. a "run" member function) to avoid the nested ifs and string
compares that you're currently doing.

Finally, you can avoid name lookups on variables and tags in gotos by
replacing these with ints.

I might have a go at doing this in Java...

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 9:24:21 AM

Cesar Rabak wrote:
> Jon Harrop escreveu:
>> Pattern matching is the single biggest advantage and is the main reason
>> why OCaml, SML, Haskell and F# are all much more concise than Common
>> Lisp. Look at the amount of code doing destructing in the above examples.
> 
> Humm... I still find your comparison loaded: you rule out the use of
> libraries for pattern matching in Lisp. Why?

Pattern matching in Lisp was in no way prohibited or even discouraged in any
of these examples. The vast majority of Lisp programmers never reach for
more sophisticated functionality, opting instead to hand code everything in
a hopelessly unmaintainable way. See Andre Thieme or Nathan Froyd's
implementations:

  http://www.lambdassociates.org/studies/study10.htm

Some people did try to use pattern matching from Lisp but it remained
uncompetitive:

Dan Bensen Greenspunned by lashing up an ad-hoc bug-ridden
informally-specified implementation of half of an ML pattern matcher for
his symbolic simplifier. His implementation remains longer and slower than
the OCaml.

Mark Tarver went the extra mile and put years of effort into making the most
sophisticated replica of modern functional programming languages for Lisp.
As you can see from these results, the Qi implementations remains slower
and longer than the OCaml.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 9:57:17 AM

> Dan Bensen escreveu:
>> Cesar Rabak wrote:
>>> Jon Harrop escreveu:
>>>> Pattern matching is the single biggest advantage and is the main
>>>> reason why OCaml, SML, Haskell and F# are all much more concise
>>>> than Common Lisp.
>>> Humm... I still find your comparison loaded: you rule out the use
>>> of libraries for pattern matching in Lisp. Why?
>> Because it sells books.
>>
> I see. . .

Actually I don't see: First I do not understand "Because it sells
books" and second, should that really refer to the fact that Jon has
written a book (and selling it for money), it still got me confused:

 1. Jon didn't hype his book in this thread.
 
 2. That someone is working in a given subject area X and actually is
    making money from it -- is that disqualifying him from making
    useful and true statements on usenet? As opposed to all the people
    around with no history in area X and no success?

I'm puzzled.

Regards -- Markus



0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/24/2007 10:03:39 AM

> Cesar Rabak wrote:
>> Jon Harrop escreveu:
>>> Pattern matching is the single biggest advantage and is the main reason
>>> why OCaml, SML, Haskell and F# are all much more concise than Common
>>> Lisp. Look at the amount of code doing destructing in the above examples.
>> 
>> Humm... I still find your comparison loaded: you rule out the use of
>> libraries for pattern matching in Lisp. Why?
>
> Pattern matching in Lisp was in no way prohibited or even discouraged in any
> of these examples. The vast majority of Lisp programmers never reach for
> more sophisticated functionality, opting instead to hand code everything in
> a hopelessly unmaintainable way. See Andre Thieme or Nathan Froyd's
> implementations:
>
>   http://www.lambdassociates.org/studies/study10.htm
>
> Some people did try to use pattern matching from Lisp but it remained
> uncompetitive:
>
> Dan Bensen Greenspunned by lashing up an ad-hoc bug-ridden
> informally-specified implementation of half of an ML pattern matcher for
> his symbolic simplifier. His implementation remains longer and slower than
> the OCaml.
>
> Mark Tarver went the extra mile and put years of effort into making the most
> sophisticated replica of modern functional programming languages for Lisp.
> As you can see from these results, the Qi implementations remains slower
> and longer than the OCaml.

Considering that Qi is more than a " replica of modern functional
programming languages" but rather (as I understood it) a framework to
define type systems, I think that last paragraph is somewhat unfair.

Regards -- Markus


0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/24/2007 10:58:41 AM

Jon Harrop wrote:

> The vast majority of Lisp programmers never
> reach for more sophisticated functionality, opting instead to hand
> code everything in a hopelessly unmaintainable way

The "vast majority" of Lisp programmers ignore you, Jonnie boy.


0
Reply david.golden (499) 7/24/2007 11:06:40 AM

Jon Harrop wrote:

> So you're saying that the comparison is grossly unfair in some
> unspecified way.

No, I was saying your programs are different.  You're desperately
trying to change the subject - you (invalidly) tried to compare
the length of your if match line and mark's, when it is clear
that they are not doing the same thing.

> I don't suppose you could be more specific? 

I don't suppose you could quit spamming comp.lang.lisp?





0
Reply david.golden (499) 7/24/2007 11:07:30 AM

> Jon Harrop wrote:
>
>> The vast majority of Lisp programmers never
>> reach for more sophisticated functionality, opting instead to hand
>> code everything in a hopelessly unmaintainable way
>
> The "vast majority" of Lisp programmers ignore you, Jonnie boy.

A certain minority of functional programmers at c.l.f. have come to
the conclusion you're a troll also, Davy. At least more than Jon is
:-).

What clued us in was the use of diminuitive names (Jonnie boy) for
your opponent and the complete lack of arguments.

And by the way, I don't whink it's quite fair to revile people and at
the same time set the f'up to alt.killfile. On a par with shouting
insults and at the same time covering your own ears with your hands:
"I can't hear you, I can't hear you". Usual age for this kind of
behaviour: ~6-12 years.

Reset F'up to comp.lang.functional. I don't have a problem with people
out there knowing that you are a troll. (and to the c.l.f crew: No
fear, I don't have the intention to exaggerate my attention to Davy).

Regards -- Markus


0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/24/2007 11:45:56 AM

Matthias Benkard schrieb:
>> the syntactic Haskell equivalent of the above
>> example would look like this:
>>    make-accumulator N = incf N
> 
> Not really.
> 
> First of all, INCF is a macro.

That's why I wrote "syntactic equivalent".
I was all talking about the overhead of having parentheses.

 > How do you curry a macro?  That doesn't make much sense to me.

I don't see any problems applying currying to macros that wouldn't apply 
to functions, or vice versa.
You can explain currying as a purely syntactic device. You can "explain 
it away" for functions by resorting to HOFs (and that's a useful 
perspective for some questions around currying), but you don't have to.

> Second, INCF takes a place as its first argument, not a value.

Seems like a macro thing to me.

> Third, INCF takes a variable number of arguments.  How is the compiler
> supposed to know wheter MAKE-ACCUMULATOR is of type Number a => a -> a
> or of type Number a => a?

There's no difference. In Haskell, make-accumulator would be exactly 
equivalent to incf.

> So yes, claiming that the above pieces of code are syntactically
> equivalent _is_ cheating (macros are part of the syntax, after all).
> You may argue about the utility of macros, but that's beside the
> point, for the fact is, Common Lisp _does_ have macros (and places,
> and variable number argument lists, both of which I find extremely
> useful), and they're not going away anytime soon.

There is no difference between a macro and a function in Haskell.

In Haskell, there is no semantic difference between compile-time and 
run-time evaluation, so any macro would be a function and vice versa. 
(That's a general property of pure languages, and not due to Haskell's 
nonstrict evaluation strategy.)
You *can* have macros in Haskell (just plop in a preprocessor), but they 
aren't nearly as pressingly needed as in an impure language. (That may 
be the reason why preprocessors are more en vogue for OCaml than for 
Haskell.)

> I have yet to see a syntax that is
> both as flexible as and more concise than that of Common Lisp.

Drop the superfluous parentheses, for example. A minimum amount of 
operator precedence and layout rules eliminates 99% of them.
That's "just lexical conciseness", you'll say, and you'd be correct. 
However, when I look at the sheer percentage of screen estate these 
parentheses are taking up, it's getting too much.

Regards,
Jo
0
Reply jo427 (1164) 7/24/2007 12:47:36 PM

Jon Harrop escreveu:
> Andr� Thieme wrote:
>> In other situations Lisp can be the better option.
>> Joel Raymond wrote about Erlangs advantages over Haskell:
>> http://wagerlabs.com/2006/1/1/haskell-vs-erlang-reloaded/
>> For example point 3.2 was talking about static typing and the extra
>> code it needed.
> 
> Look at the vector record and zero vector definition from my ray tracer. In
> Lisp:
> 
> (defstruct (vec (:conc-name nil)
>                 (:constructor vec (x y z))
>                 (:type (vector double-float)))
>   x y z)
> 
> (defvar zero (vec 0d0 0d0 0d0))
> 
> In OCaml:
> 
> type vec = {x:float; y:float; z:float}
> let zero = {x=0.; y=0.; z=0.}
> 
For a LOC counting perpective, both snippets above have the same count: 
2 logical lines.
0
Reply csrabak (393) 7/24/2007 12:54:48 PM

Jon Harrop schrieb:
> Joachim Durchholz wrote:
>> There are two answers to that:
>>
>> 1. Coding doesn't take longer,
> 
> Even if there is four times as much code?

Not enough of a difference to get above the noise level.
I spend 90% of my programming time designing things. (The other 90% are 
debugging and maintenance, of course *g*)

I also happen to be a rather adept blind typist, so I wouldn't even 
*think* about the parentheses.

>> 2. You can always count nodes in the AST instead of lines of code.
> 
> Lisp's verbosity stems primarily from its use of whitespace and parentheses
> as well as a lack of pattern matching.

Ah, right, lack of pattern matching tends to bloat any code.
I didn't notice this since the example code given didn't have any case 
distinctions.

I'm still surprised it isn't already in widespread use in any new 
language. I've been seriously missing that in any language that I've 
been using since I got to know the concept (and even before).

 > You can see this in almost any
> comparable programs written in the two languages (or any languages with the
> similar features, e.g. Haskell vs Scheme). Look at the intersect routines
> from my ray tracer. First the Lisp:
> 
> (defun intersect (orig dir scene)
>   (labels ((aux (lam normal scene)
>              (let* ((center (sphere-center scene))
>                     (lamt (ray-sphere orig
>                                       dir
>                                       center
>                                       (sphere-radius scene))))
>                (if (>= lamt lam)
>                    (values lam normal)
>                    (etypecase scene
>                      (group
>                       (dolist (kid (group-children scene))
>                         (setf (values lam normal)
>                               (aux lam normal kid)))
>                       (values lam normal))
>                      (sphere
>                       (values lamt (unitise
>                                     (-v (+v orig (*v lamt dir)) center)))))))))
>     (aux infinity zero scene)))
> 
> Then the OCaml:
> 
> let rec intersect o d (l, _ as hit) (c, r, s) =
>   let l' = ray_sphere o d c s in
>   if l' >= l then hit else match s with
>     [] -> l', unitise (o +| l' *| d -| c)
>   | ss -> List.fold_left (intersect o d) hit ss

I think the Lisp would look better if it weren'd indented so much.
It might even get slightly shorter because some stuff could be written 
inline.
(I can't say whether the above Lisp could be written more concisely though.)

>> For 
>> the above example, you'd end up at roughly the same figures for Lisp and
>> your generic FPL, but as soon as you declare macros in Lisp, the FPL
>> needs less nodes.
> 
> Are you saying that macros reduce code size?

First, I'm (wrongly) assuming that Lisp's relative verboseness comes 
from parentheses (and additional whitespace needed because those 
parentheses force you into more line wraps).

Seconds, I'm saying that needing macros means that you often writen the 
same semantics twice, once as a function and once (for those cases where 
it's a useful optimization) as a macro.
So a language that works well without macros is shorter.
(I assume that macros are more a library thing, not something that gets 
written routinely or redundantly, so I don't think the effect is large.)

So, no, I'm saying that needing macros tends to increase code size, 
though I can't say it would be much and suspect it isn't much indeed.

Regards,
Jo
0
Reply jo427 (1164) 7/24/2007 12:59:20 PM

David Golden schrieb:
> 
> Very, very lame, Jonnie boy.

Plonk.

0
Reply jo427 (1164) 7/24/2007 1:01:16 PM

Tony Finch schrieb:
> I think the comparison would be fairer if you used the same variable names
> in each language. You've used words in the Lisp and single letters in the
> O'Caml, which undermines your argument.

Only partly.
In shorter code, fully descriptive names aren't as relevant since you 
have fewer lines to check for cross-referencing code.
I see these name terseness elsewhere in functional code, including code 
from people who are generally considered as "writing good style". (Take 
a look at the Haskell Prelude, for example.)

Regards,
Jo
0
Reply jo427 (1164) 7/24/2007 1:09:45 PM

Cesar Rabak schrieb:
> Humm... I still find your comparison loaded: you rule out the use of 
> libraries for pattern matching in Lisp. Why?

My answer would be:

Using a pattern matching library adds yet another dependency to your 
code. Unless you know that the library is well-maintained, you don't 
want this kind of dependency.

In other words, I suspect it would find lots of use it if became part of 
the CLOS standard.

Regards,
Jo
0
Reply jo427 (1164) 7/24/2007 1:13:26 PM

Joachim Durchholz wrote:

> Drop the superfluous parentheses, for example. A minimum amount of 
> operator precedence and layout rules eliminates 99% of them.

And makes the code massively more annoying to read. In fact,
the baroque syntax is the main reason I dislike Haskell (Liskell borders
on interesting though, there might be a reasonable language buried
underneath the syntax afflicting Haskell).  I find Lisp,  Forth and APL 
pleasant to read largely due to their simple syntax without complicated
precedence. You may be  different, but not everyone's preferences are
the same.





0
Reply david.golden (499) 7/24/2007 1:15:54 PM

> David Golden schrieb:
>> Very, very lame, Jonnie boy.
>
> Plonk.

Plonking is too good for 'em trolls. :-).

Regards -- Markus


0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/24/2007 1:33:56 PM

Jon Harrop <jon@ffconsultancy.com> writes:
>Yes. I get a lot of errors when I try to compile it:

  Sorry - I was using non-standard identifier notation and was
  not aware that someone else would want to compile this.

  Here is the more recent version without this identifier
  notation and with some improvements for efficiency. It also
  has a slight unfair advantage in that it does not accept the
  whole language but just the operators used in the example
  program:

// uses http://www.purl.org/stefan_ram/pub/ram-jar
import de.dclj.ram.notation.unotal.RoomSource;
import static de.dclj.ram.notation.unotal.RoomFromModule.roomFrom;
import static java.lang.System.out;
import static java.lang.System.nanoTime;
import static java.lang.Thread.sleep;

public class Main
{ public static void main( final java.lang.String[] args )
  throws java.lang.Throwable // refers to the sleep call below
  {
    sleep( 3000 );
    final long t0 = nanoTime();

    final Input input = new Input();
    final State state = new State( input );
    boolean running = true; while( running )
    { final java.lang.Object sourceEntry = state.currentEntry();
      if( sourceEntry instanceof RoomSource )
      { final Symbol statement = new Symbol( sourceEntry );
        running = running && execute( statement, state ); }
      ++state.sourcePos;
      if( state.empty() )running = false; }

    final long t1 = nanoTime();
    final long diff =( t1 - t0 );
    out.printf( "%n%f%n", diff / 1E9 ); }

  static boolean execute( final Symbol statement, final State state )
  { boolean running = true;
    if( false );
    else if( statement.of( "if" ))
    { execute
      ( new Symbol
        ( statement.room( value( statement.room( 0 ), state ) == 0 ? 4 : 2 )),
        state ); }
    else if( statement.of( "goto" ))
    { state.goTo( statement.string( 0 )); }
    else if( statement.of( "--" ))
    { state.value.get( statement.string( 0 ))[ 0 ]--; }
    else if( statement.of( "++" ))
    { state.value.get( statement.string( 0 ))[ 0 ]++; }
    else if( statement.of( "end" ))
    { running = false; }
    else if( statement.of( "print" ))
    { java.lang.System.out.println
      ( state.value.containsKey( statement.string( 0 ))?
        value( statement.string( 0 ), state ) : statement.string( 0 )); }
    else if( statement.of( "input" ))
    { state.value.put
      ( statement.string( 0 ), new int[]{ java.lang.Integer.valueOf
          (( java.lang.String )state.input.data.get( state.inputPos++ ))}); }
    return running; }

  static int value( final java.lang.Object object, final State state )
  { int result = java.lang.Integer.MIN_VALUE;
    if( object instanceof java.lang.String )
    { final java.lang.String string =( java.lang.String )object;
      if( string.matches( "[0-9]+" ))
      { result = java.lang.Integer.valueOf( string ); }
      else
      { result = state.value.get( string )[ 0 ]; }}
    else
    { final Symbol expression = new Symbol( object );
      if( expression.of( "eq" ))
      { final int l = value( expression.operand( 0 ), state );
        final int r = value( expression.operand( 1 ), state );
        result = l == r ? -1 : 0; }}
    return result; }}

class Input
{ final RoomSource source = roomFrom
  // To read from a file, use a java.io.File-object as argument
  // instead of a string as below.
  ( "                                                                     " +
    "                                                                     " +
    "                                                                     " +
    "       < < print [Add x and y] >                                     " +
    "                                                                     " +
    "         < print [Input x: ] >                                       " +
    "         < input x >                                                 " +
    "                                                                     " +
    "         < print [Input y: ] >                                       " +
    "         < input y >                                                 " +
    "                                                                     " +
    "         main                                                        " +
    "         < if< x eq 0 >then< goto end >else< goto sub1x >>           " +
    "                                                                     " +
    "         sub1x                                                       " +
    "         < -- x >                                                    " +
    "         < ++ y >                                                    " +
    "         < goto main >                                               " +
    "                                                                     " +
    "         end                                                         " +
    "         < print [The total of x and y is ] >                        " +
    "         < print y >                                                 " +
    "                                                                     " +
    "         >                                                           " +
    "                                                                     " +
    "                                                                     " +
    "                                                                     " );
  final RoomSource data = roomFrom
  ( "< 100000 100000 >" ); }

class State
{ public final Input input;
  public State( final Input input )
  { this.input = input;
    for( int i = 0; i < input.source.length(); ++i )
    if( this.input.source.get( i ) instanceof java.lang.String )
    this.line.put(( java.lang.String )this.input.source.get( i ), new int[]{ i } ); }
  public final java.util.Map<java.lang.String,int[]> value =
  new java.util.HashMap<java.lang.String,int[]>();
  public final java.util.Map<java.lang.String,int[]> line =
  new java.util.HashMap<java.lang.String,int[]>();
  int sourcePos = 0;
  int inputPos = 0;
  public void goTo( final java.lang.String label )
  { this.sourcePos = line.get( label )[ 0 ]; }
  public java.lang.Object currentEntry()
  { return this.input.source.get( this.sourcePos ); }
  public boolean empty()
  { return this.sourcePos >= this.input.source.length(); }}

class Symbol
{ java.lang.String keyword = null;
  int keywordPos = -1;
  RoomSource source = null;
  public Symbol( final java.lang.Object entry )
  { source =( RoomSource )entry;
    keywordPos = 0;
    keyword =( java.lang.String )source.get( 0 );
    if( source.length() > 1 &&
      source.get( 1 )instanceof java.lang.String )
    { final java.lang.String cadr =( java.lang.String )source.get( 1 );
      if( cadr.length() <= 3 && cadr.length() > 1 &&
        ( "and".equals( cadr ) || "or".equals( cadr ) ||
          "is".equals( cadr ) || "eq".equals( cadr )))
      { keywordPos = 1; keyword = cadr; }}}
  public final java.lang.String keyword(){ return this.keyword; }
  public final boolean of( final java.lang.String string )
  { return string.equals( this.keyword() ); }
  public final java.lang.Object operand( int pos )
  { if( pos >= keywordPos )++pos;
    return this.source.get( pos ); }
  public final java.lang.String string( final int pos )
  { return( java.lang.String )this.operand( pos ); }
  public final RoomSource room( final int pos )
  { return( RoomSource )this.operand( pos ); }
  public final java.lang.String toString()
  { return this.source.toString(); }}


0
Reply ram (2828) 7/24/2007 1:39:02 PM

Joachim Durchholz <jo@durchholz.org> writes:
>> I have yet to see a syntax that is
>> both as flexible as and more concise than that of Common Lisp.
>
> Drop the superfluous parentheses, for example. A minimum amount of
> operator precedence and layout rules eliminates 99% of them.

Oops!  Now you'll have to teach this minimum amount of operator
precedence and layout rules to the billions of macros out there.

And each macro will become much bigger and more complex...

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Wanna go outside.
Oh, no! Help! I got outside!
Let me back inside!
0
Reply pjb (7647) 7/24/2007 1:40:10 PM

> Ah, right, lack of pattern matching tends to bloat any code.
> I didn't notice this since the example code given didn't have any case
> distinctions.
>
> I'm still surprised it isn't already in widespread use in any new
> language. I've been seriously missing that in any language that I've
> been using since I got to know the concept (and even before).

I completely agree with that. Not only that the code becomes longer,
but I think the destructuring of values becomes easier to see than in
multiple nested conditional statements and explicit selector functions
in the branches.

This is no statement against Lisp or Scheme, but just compare

  match l with 
      []     -> ... 
    | h::t   -> ...

with (something like)

(if (is_empty l) 
    ( ... )
    ( ... (car l) ... (cdr l) ... ))

and IMHO it becomes much worse if there are more than 2 cases.

Regards -- Markus

0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/24/2007 1:58:29 PM

On Jul 24, 2:15 am, Ulf Wiger <etxu...@cbe.ericsson.se> wrote:
> A paper at the upcoming ICFP conference will present a more
> systematic comparison between C++, Erlang and Haskell.
> It shows some interesting stuff, but also warns against too
> far-reaching conclusions.
>
> Evaluating High-Level Distributed Language Constructs
>     by Jan Nystrom, Phil Trinder, David King


Brief discussion and a link to that paper can be found here:
http://lambda-the-ultimate.org/node/2287

Just the paper:
http://www.macs.hw.ac.uk/~trinder/papers/ICFP2007.pdf

0
Reply don.dwoske (6) 7/24/2007 2:00:15 PM

> Tony Finch schrieb:
>> I think the comparison would be fairer if you used the same variable names
>> in each language. You've used words in the Lisp and single letters in the
>> O'Caml, which undermines your argument.
>
> Only partly.
> In shorter code, fully descriptive names aren't as relevant since you

Rule of thumb for me: The larger the scope the more descriptive the
variable name should be. Actually modify that by how far away the
corresponding type definitions have been made:

  let f l = ...  (* bad *)

  let f customer_list = ... (* better *)

  let f (customers : customer list) = ...  (* best *)


But 

  let f (customers ...) =

     ...

     let process cs ... =
         ...

     in 

         process customers ... ;;


because all information is there locally to derive what 'cs' is.

> have fewer lines to check for cross-referencing code.
> I see these name terseness elsewhere in functional code, including
> code from people who are generally considered as "writing good
> style". (Take a look at the Haskell Prelude, for example.)

:-).

I think this is a bit like naming conventions in physics: Even in
printed texts, it's always V that is used for voltage. In the same
spirit I use n,k,i for integers and l (or sometimes haskell style 'xs'
or 'as') for (local) variables. Of course code becomes less
understandable for other people this way, but that's what types are
for (so I try to choose descriptive type names and then l, being of
type 'customer list' is immediately understandable again).

Regards -- Markus
0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/24/2007 2:05:45 PM

In article <<7x4pjuf9w5.fsf@ruckus.brouhaha.com>>,
Paul Rubin <> wrote:
> 
> You can't do anything of the sort.  Consider that Haskell has no
> language support for exceptions or continuations, because they're
> implemented straightforwardly as library modules, using a
> combination of lazy evaluation and currying.  They can't be
> implemented that way in Lisp, so exceptions are built into the
> language and continuations (in CL) can't be done at all without
> nonstandard extensions.

Continuations can definitely be implemented in Lisp to the same extent
that they are in Haskell. What Haskell's continuation module provides
is a nice, strongly-typed interface to code in continuation passing
style. It does *not* let you capture arbitrary continuations, the way
you can in Scheme.

Being able to conveniently program in CPS is a good thing, IMO, but a)
I certainly wouldn't call it full support for continuations, and b)
you can program in CPS in any Lisp with tail call optimization.

-- 
Neel R. Krishnaswami
neelk@cs.cmu.edu
0
Reply neelk (298) 7/24/2007 2:35:44 PM

David Golden wrote:
> Jon Harrop wrote:
>> So you're saying that the comparison is grossly unfair in some
>> unspecified way.
> 
> No, I was saying your programs are different.  You're desperately
> trying to change the subject - you (invalidly) tried to compare
> the length of your if match line and mark's, when it is clear
> that they are not doing the same thing.

What exactly do you believe they are doing differently?

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 2:49:52 PM

Pascal Bourguignon wrote:
> Joachim Durchholz <jo@durchholz.org> writes:
>>> I have yet to see a syntax that is
>>> both as flexible as and more concise than that of Common Lisp.
>>
>> Drop the superfluous parentheses, for example. A minimum amount of
>> operator precedence and layout rules eliminates 99% of them.
> 
> Oops!  Now you'll have to teach this minimum amount of operator
> precedence and layout rules to the billions of macros out there.
> 
> And each macro will become much bigger and more complex...

OCaml and Haskell already handle this just fine.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 2:51:00 PM

David Golden wrote:
> And makes the code massively more annoying to read. In fact,
> the baroque syntax is the main reason I dislike Haskell (Liskell borders
> on interesting though, there might be a reasonable language buried
> underneath the syntax afflicting Haskell).  I find Lisp,  Forth and APL
> pleasant to read largely due to their simple syntax without complicated
> precedence. You may be  different, but not everyone's preferences are
> the same.

Right. This is a really a reflection of modern statically-typed FPLs being
languages for smart people. If you're still struggling with the precedence
of + and * then you've little hope of mastering any non-trivial type
system.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 2:53:32 PM

Cesar Rabak <csrabak@yahoo.com.br> writes:

>> (defstruct (vec (:conc-name nil)
>>                 (:constructor vec (x y z))
>>                 (:type (vector double-float)))
>>   x y z)
>>
>> (defvar zero (vec 0d0 0d0 0d0))
>>
>> In OCaml:
>>
>> type vec = {x:float; y:float; z:float}
>> let zero = {x=0.; y=0.; z=0.}
>>
> For a LOC counting perpective, both snippets above have the same count: 2
> logical lines.

You should write a paper introducing this brilliant new code metric of
"logical lines" (my I suggest "PROGN the ultimate 1-liner" for a title?).

'as
0
Reply a.schmolck5284 (241) 7/24/2007 2:55:42 PM

Joachim Durchholz wrote:
> Jon Harrop schrieb:
>> Even if there is four times as much code?
> 
> Not enough of a difference to get above the noise level.

No way. You really wouldn't rather inherit 100kLOC of code that does the
same thing as 400kLOC of code?

>>> 2. You can always count nodes in the AST instead of lines of code.
>> 
>> Lisp's verbosity stems primarily from its use of whitespace and
>> parentheses as well as a lack of pattern matching.
> 
> Ah, right, lack of pattern matching tends to bloat any code.
> I didn't notice this since the example code given didn't have any case
> distinctions.

Yes. An important point here is the fact that pattern matching is used
ubiquitously for decomposition as well as dynamic dispatch when available.

> I'm still surprised it isn't already in widespread use in any new
> language. I've been seriously missing that in any language that I've
> been using since I got to know the concept (and even before).

Indeed.

> ...
> I think the Lisp would look better if it weren'd indented so much.

I like LOC because I think it is absurd to split a trivial if expression
over several lines.

>>> For
>>> the above example, you'd end up at roughly the same figures for Lisp and
>>> your generic FPL, but as soon as you declare macros in Lisp, the FPL
>>> needs less nodes.
>> 
>> Are you saying that macros reduce code size?
> 
> First, I'm (wrongly) assuming that Lisp's relative verboseness comes
> from parentheses (and additional whitespace needed because those
> parentheses force you into more line wraps).

Yes. I that is another big effect.

> Seconds, I'm saying that needing macros means that you often writen the
> same semantics twice, once as a function and once (for those cases where
> it's a useful optimization) as a macro.
> So a language that works well without macros is shorter.
> (I assume that macros are more a library thing, not something that gets
> written routinely or redundantly, so I don't think the effect is large.)
> 
> So, no, I'm saying that needing macros tends to increase code size,
> though I can't say it would be much and suspect it isn't much indeed.

Yes. I think macros can be nice for aesthetics but they are easily overused
and abused for things like optimization.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 3:43:53 PM

Neelakantan Krishnaswami wrote:
> Being able to conveniently program in CPS is a good thing, IMO,

Depends what the trade-off is, IMHO.

> but a) 
> I certainly wouldn't call it full support for continuations, and b)
> you can program in CPS in any Lisp with tail call optimization.

Sure. But Lisp doesn't require tail calls and does require dynamic binding
which undermines tail calls so few Lisps actually do tail calls and there
is no standard.

  http://www.cliki.net/Tail Recursion

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 3:51:03 PM

Paul Rubin wrote:
> Andr� Thieme <address.good.until.2007.dec.26@justmail.de> writes:
>> In Lisp you could do the same. You could teach Lisp implicit currying
>> and also implicit lazyness (altough I think that it would feel really bad).
> 
> You can't do anything of the sort.  Consider that Haskell has no
> language support for exceptions or continuations, because they're
> implemented straightforwardly as library modules, using a combination
> of lazy evaluation and currying.  They can't be implemented that way
> in Lisp, so exceptions are built into the language

No, exceptions can be implemented in a Common Lisp without exceptions 
already built in. For example, see 
http://www.nhplace.com/kent/CL/Revision-18.lisp

They are built into ANSI Common Lisp because (a) ANSI Common Lisp 
doesn't make a distinction between built-in and library functionality 
and (b) it's important that the same condition system is used throughout 
your program, so that libraries can more easily react to exceptions from 
other libraries.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/24/2007 3:54:37 PM

Pascal Costanza wrote:
> No, exceptions can be implemented in a Common Lisp without exceptions
> already built in. For example, see
> http://www.nhplace.com/kent/CL/Revision-18.lisp

Turing argument.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 4:03:49 PM

Joachim Durchholz <jo@durchholz.org> writes:

> takes less of a line; the syntactic Haskell equivalent of the above
> example would look like this:
>    make-accumulator N = incf N

This is incorrect for several reasons, the most obvious being the lack
of accounting for the variable arity of incf...


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
0
Reply nospam3258 (1248) 7/24/2007 4:05:53 PM

Joachim Durchholz wrote:

> In other words, I suspect it would find lots of use it if became part
> of the CLOS standard.
> 

You say "it", but pattern matching exists in quite a number of forms.
Should some cut-down one-sided matcher be standardised, very vaguely
akin to a decision to standardise on single-dispatch OO?  Should
matching be only on typed data (and thus should the Lisp type system be
beefed up before hand?), or should matching/unification be over more
arbitrary structure? Should there be some sort of a "meta match
protocol"? (for experimenting with controlled extension for matching
shape in mobile processes. Or something.)

Right now, there are several pattern matching or unification
libraries for lisp (sometimes as a relatively minor part of a larger
project). With different tradeoffs and powers.  The situation may well
be loosely analogous to some pre-clos-standardisation state of lisp
object systems.  You might say "pick one and move on". But I reckon
it's just too early.















 






0
Reply david.golden (499) 7/24/2007 4:09:19 PM

Jonnie boy wrote:

> If you're still struggling with the 
> precedence of + and * 

I don't "struggle".  I just regard it as annoying.  Do you
struggle with a crane fly?  No, of course not, anyone
could end their tiny life with trivial effort.  Does that stop 
them being vaguely annoying? No.







0
Reply david.golden (499) 7/24/2007 4:10:50 PM

David Golden wrote:
> You say "it", but pattern matching exists in quite a number of forms.
> Should some cut-down one-sided matcher be standardised, very vaguely
> akin to a decision to standardise on single-dispatch OO?  Should
> matching be only on typed data (and thus should the Lisp type system be
> beefed up before hand?), or should matching/unification be over more
> arbitrary structure? Should there be some sort of a "meta match
> protocol"? (for experimenting with controlled extension for matching
> shape in mobile processes. Or something.)
> 
> Right now, there are several pattern matching or unification
> libraries for lisp (sometimes as a relatively minor part of a larger
> project). With different tradeoffs and powers.  The situation may well
> be loosely analogous to some pre-clos-standardisation state of lisp
> object systems.  You might say "pick one and move on". But I reckon
> it's just too early.

You could just copy F#.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 4:12:10 PM

Jon Harrop wrote:

> Lisp doesn't require tail calls and does require dynamic binding
> which undermines tail calls so few Lisps actually do tail calls and there
> is no standard.

Most Common Lisp implementations support tail call optimization in one 
form or the other. It is true that there is no standard way to ensure 
this, but saying that few Lisps do this is definitely wrong.

Dynamically scoped variables don't undermine tail calls either.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/24/2007 4:15:31 PM

Jon Harrop wrote:
> Pascal Costanza wrote:
>> No, exceptions can be implemented in a Common Lisp without exceptions
>> already built in. For example, see
>> http://www.nhplace.com/kent/CL/Revision-18.lisp
> 
> Turing argument.

Quoted out of context.

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/24/2007 4:16:28 PM

David Golden wrote:
> I don't "struggle".  I just regard it as annoying.

If you find 1+2 "annoying" then I doubt even Lisp can help.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 4:18:03 PM

Joachim Durchholz wrote:
> David Golden schrieb:
>> Joachim Durchholz wrote:
>> 
>>> Drop the superfluous parentheses, for example. A minimum amount of
>>> operator precedence and layout rules eliminates 99% of them.
>> 
>> And makes the code massively more annoying to read. In fact,
>> the baroque syntax is the main reason I dislike Haskell
> 
> That's just as silly as saying "Lisp is unreadable because of those Lots
> of Irritating Superfluous Parentheses".

No. Having excessive parentheses is definitely sillier.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 4:20:13 PM

David Golden schrieb:
> Joachim Durchholz wrote:
> 
>> Drop the superfluous parentheses, for example. A minimum amount of 
>> operator precedence and layout rules eliminates 99% of them.
> 
> And makes the code massively more annoying to read. In fact,
> the baroque syntax is the main reason I dislike Haskell

That's just as silly as saying "Lisp is unreadable because of those Lots 
of Irritating Superfluous Parentheses".

Regards,
Jo
0
Reply jo427 (1164) 7/24/2007 4:27:36 PM

On Jul 24, 5:59 am, Joachim Durchholz <j...@durchholz.org> wrote:
> Seconds, I'm saying that needing macros means that you often writen the
> same semantics twice, once as a function and once (for those cases where
> it's a useful optimization) as a macro.

(1) One doesn't "need" macros any more than one "needs" iteration
statments - both are merely more convenient than the alternatives in
certain situations.
(2) "often"?  I almost never write something as both a macro and a
function.  In fact, the whole point of writing something as a macro is
usually that there's no reasonable way to write the semantics as a
function.

For example, consider python 2.6's "with" statement.  There's no clean
way to write it as a function, so pre 2.6 code basically repeats
with's definition everywhere the functionality is used.

-andy

0
Reply anamax (170) 7/24/2007 4:41:04 PM

Pascal Bourguignon schrieb:
> Joachim Durchholz <jo@durchholz.org> writes:
>>> I have yet to see a syntax that is
>>> both as flexible as and more concise than that of Common Lisp.
>> Drop the superfluous parentheses, for example. A minimum amount of
>> operator precedence and layout rules eliminates 99% of them.
> 
> Oops!  Now you'll have to teach this minimum amount of operator
> precedence and layout rules to the billions of macros out there.

Nonsense. Stick with a few hard-and-fast rules, and you can get rid of 
most parentheses.
The usual arithmetic/comparison/boolean/definitional hierarchy will do 
fine, with the additional twist that juxtaposition is an operator that 
binds most tightly (so sin x + 5 is (sin x) + 5, just as mathematical 
tradition would have it).

User-defined operators shouldn't get additional precedences. Unless 
you're doing an embedded language and have collected a *lot* empirical 
data about operator usage in it, and are quite confident that you got 
the precedences right. (Even Pascal got the relative precedence of 
boolean and comparison operators wrong. And Niklas Wirth certainly has 
spent a great deal of care on that one.)

Oh, and actually precedence shouldn't be attached to the function 
definitions but to the operator symbols. We're talking initial parsing 
here (whether by humand or machine), that's the step that happens before 
semantics of any kind comes into play.
Even if you redefine +, it should keep its precedence level after all...

Regards,
Jo
0
Reply jo427 (1164) 7/24/2007 4:42:34 PM

David Golden schrieb:
> Joachim Durchholz wrote:
> 
>> In other words, I suspect it would find lots of use it if became part
>> of the CLOS standard.
>>
> 
> You say "it", but pattern matching exists in quite a number of forms.
> Should some cut-down one-sided matcher be standardised, very vaguely
> akin to a decision to standardise on single-dispatch OO?  Should
> matching be only on typed data (and thus should the Lisp type system be
> beefed up before hand?), or should matching/unification be over more
> arbitrary structure? Should there be some sort of a "meta match
> protocol"? (for experimenting with controlled extension for matching
> shape in mobile processes. Or something.)

Oh, the vagaries of too much design space!

How about a library that leaves all these design options open for 
Lispers to explore? I always thought you can do anything in Lisp, no?

> Right now, there are several pattern matching or unification
> libraries for lisp (sometimes as a relatively minor part of a larger
> project). With different tradeoffs and powers.

I have looked at one or two of them, and what I found was more a 
trade-off of available developer time vs. "get it right in the first place".
Which is, I think, one of the reasons such libraries aren't in 
widespread use outside of the project that they were initially written for.

 > The situation may well
> be loosely analogous to some pre-clos-standardisation state of lisp
> object systems.  You might say "pick one and move on". But I reckon
> it's just too early.

Well, maybe.
It still seems to be part of a large NIH syndrome. Lisp isn't the only 
language that fails to pick up this lead. (Well, maybe Perl 6... though 
it will have to name it differently than "pattern matching", because all 
those Perl golfers out there will immediately misunderstand the term.)

Regards,
Jo
0
Reply jo427 (1164) 7/24/2007 4:47:09 PM

Joachim Durchholz wrote:
> Frankly, I wouldn't care whether the imported code is 100kLoC or
> 400kLoC. I'd care more whether it's stable and has a healthy community.

All other things being equal.

> The situation wasn't about importing code anyway, it was about writing
> it. And for that, a factor-4 blowup isn't exactly what I'd like, but
> it's definitely not a show stopper. Not if the AST is the same (I'd moan
> about it, of course, but I've been writing 250kB of PHP without too much
> pain in the past two years, and PHP is worse than anything we've been
> discussing here!)

The ASTs are wildly different here. I wasn't referring to syntactic
differences. The Lispers compiled their pattern matches by hand and they
would have to maintain that by hand. Similarly, Java programmers would code
lots of unnecessary classes and inheritance hierarchies by hand and would
have to maintain those.

The differences in verbosity are more than skin deep...

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/24/2007 4:47:57 PM

Jon Harrop schrieb:
> Joachim Durchholz wrote:
>> Jon Harrop schrieb:
>>> Even if there is four times as much code?
>> Not enough of a difference to get above the noise level.
> 
> No way. You really wouldn't rather inherit 100kLOC of code that does the
> same thing as 400kLOC of code?

Frankly, I wouldn't care whether the imported code is 100kLoC or 
400kLoC. I'd care more whether it's stable and has a healthy community.

The situation wasn't about importing code anyway, it was about writing 
it. And for that, a factor-4 blowup isn't exactly what I'd like, but 
it's definitely not a show stopper. Not if the AST is the same (I'd moan 
about it, of course, but I've been writing 250kB of PHP without too much 
pain in the past two years, and PHP is worse than anything we've been 
discussing here!)

Regards,
Jo
0
Reply jo427 (1164) 7/24/2007 4:51:02 PM

jayessay schrieb:
> Joachim Durchholz <jo@durchholz.org> writes:
> 
>> takes less of a line; the syntactic Haskell equivalent of the above
>> example would look like this:
>>    make-accumulator N = incf N
> 
> This is incorrect for several reasons, the most obvious being the lack
> of accounting for the variable arity of incf...

Haskell is a currying language, so at least this counterargument doesn't 
hold.

With some handwaving, the above could could be written as

   make-accumulator N ... = incf N ...

with the understanding that the three dots stand for an arbitrary number 
of parameters to be copied through verbatim from left to right.

Actually, in Haskell,

   make-accumulator N = incf N

is equivalent to

   make-accumulator = incf

with the sole exception that the first declaration forces 
make-accumulator to have at least one parameter.

Hope this clears it up a little.

Regards,
Jo
0
Reply jo427 (1164) 7/24/2007 4:55:45 PM

Joachim Durchholz <jo@durchholz.org> writes:

> jayessay schrieb:
> > Joachim Durchholz <jo@durchholz.org> writes:
> >
> >> takes less of a line; the syntactic Haskell equivalent of the above
> >> example would look like this:
> >>    make-accumulator N = incf N
> > This is incorrect for several reasons, the most obvious being the
> > lack
> > of accounting for the variable arity of incf...
> 
> Haskell is a currying language, so at least this counterargument
> doesn't hold.
> 
> With some handwaving, the above could could be written as
> 
>    make-accumulator N ... = incf N ...
> 
> with the understanding that the three dots stand for an arbitrary
> number of parameters to be copied through verbatim from left to right.

Isn't the "handwaving" aspect the point?, i.e., I don't think anyone
is saying you can't do this, but simply that what you wrote was _not_
equivalent.


>    make-accumulator N = incf N
> 
> is equivalent to
> 
>    make-accumulator = incf

The N is not the issue - it was the missing i.


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
0
Reply nospam3258 (1248) 7/24/2007 5:09:01 PM


> Isn't the "handwaving" aspect the point?, i.e., I don't think anyone
> is saying you can't do this, but simply that what you wrote was _not_
> equivalent.

Equivalent in which sense? 

Regards -- Markus

0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/24/2007 5:26:56 PM

Joachim Durchholz <jo@durchholz.org> writes:

> Pascal Bourguignon schrieb:
>> Joachim Durchholz <jo@durchholz.org> writes:
>>>> I have yet to see a syntax that is
>>>> both as flexible as and more concise than that of Common Lisp.
>>> Drop the superfluous parentheses, for example. A minimum amount of
>>> operator precedence and layout rules eliminates 99% of them.
>>
>> Oops!  Now you'll have to teach this minimum amount of operator
>> precedence and layout rules to the billions of macros out there.
>
> Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
> most parentheses.

Like in:

  #define a(x,y) x*y

perhaps?

To be able to use this macro as:

  (int)a(1.0+2.0,3.0+4.0)

you need to actually define it as:

  #define a(x,y) ((x)*(y))

so much for operator precedence and layout rules.

In lisp, you merely write it as:

  (defmacro a (x y) `(* ,x ,y))

less parentheses than in C!

 
-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

THIS IS A 100% MATTER PRODUCT: In the unlikely event that this
merchandise should contact antimatter in any form, a catastrophic
explosion will result.
0
Reply pjb (7647) 7/24/2007 5:37:12 PM

Alexander Schmolck escreveu:
> Cesar Rabak <csrabak@yahoo.com.br> writes:
> 
>>> (defstruct (vec (:conc-name nil)
>>>                 (:constructor vec (x y z))
>>>                 (:type (vector double-float)))
>>>   x y z)
>>>
>>> (defvar zero (vec 0d0 0d0 0d0))
>>>
>>> In OCaml:
>>>
>>> type vec = {x:float; y:float; z:float}
>>> let zero = {x=0.; y=0.; z=0.}
>>>
>> For a LOC counting perpective, both snippets above have the same count: 2
>> logical lines.
> 
> You should write a paper introducing this brilliant new code metric of
> "logical lines" (my I suggest "PROGN the ultimate 1-liner" for a title?).
> 
I regret inform that this has already been done, and it is a practice 
used for companies for 'benchmarking' productivity and make 
approximations against the useful program result in Function Points. The 
technique is called "backfiring" and has almost twenty years.

The idea behind it is to avoid the noise coming from different 
indentation styles, continuation of a (logical) line in more than a 
physical line and the converse (having more than a logical line in the 
same physical one).

0
Reply csrabak (393) 7/24/2007 5:54:01 PM

ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Here is a Java implementation.

You have a truly unique style of writing and formatting your Java
code. It took me a few moments to get accustomed to it, but it is
readable. Aside from similarities to idiomatic Lisp, it reminds me of
Dinkumware's style used in their C++ libraries. Take that as a
compliment.

-- 
Steven E. Harris
0
Reply seh (245) 7/24/2007 6:09:51 PM

Paul Rubin schrieb:
> Matthias Benkard <mulkiatsch@gmail.com> writes:
>> First of all, INCF is a macro.  How do you curry a macro?  That
>> doesn't make much sense to me.
> 
> incf is a macro because macros are the only way to make Lisp forms
> that don't evaluate their args.

This is half true. What happens in Haskell automatically is what you
have to do in ML and Lisp manually - embed code blocks in an (anonymous)
function object. In Lisp you can provide your own version of eval and
make code lazy by default.


> Haskell uses lazy evaluation and
> therefore all kinds of things that Lisp uses macros for, are done in
> Haskell as ordinary functions.

I think most trivial macros can be done with this lazy way in Haskell.
At the cost of runtime overhead.
One example are reader macros.
People sometimes complain about mathmatical notation in Lisp.
I complain about the one in other programming languages. In Lisp one
would write [7x₆ + 9π³ - 6ˣ]
vs          7*x[6] + 9*pi*pi*pi - pow(6, x)

Of course you could do the same in Haskell:
readableMath"7x₆ + 9π³ - 6ˣ"

At runtime some parser would begin its work. In Lisp it gets translated
into efficient machine code at compile time. But if someone wants he/she
could do it the same way as an OCaml or Haskell or Erlang user would.
I am also not sure how the less than 16 LOC of
http://www.gigamonkeys.com/book/practical-building-a-unit-test-framework.html
would look in one of these languages.


> Of course incf mutates its argument,
> which normally isn't done in Haskell.  So you'd only code something
> like incf as a monad action.

Would you provide the one liner that is doing incf?


André
-- 
0
Reply address.good.until.2007.dec.26 (60) 7/24/2007 6:13:11 PM

Joachim Durchholz wrote:

> How about a library that leaves all these design options open for
> Lispers to explore?

That's what I was getting at with "meta match protocol", you might
have to be familiar with CLOS jargon to recognise that, granted.
(the meta object protocol allowing for the perversion of CLOS in a
controlled and portable fashion...)

> Well, maybe.
> It still seems to be part of a large NIH syndrome. 

Hmm. if anything, I'd say the lisp community was a pretty early adopter
of various matching functionalities (think of all the embedded
prologoids smushed into lisp apps over the years for starters).
(N.B. don't mistake  lack-of/facetious/hostile response to Harrop in
particular as disdain for all pattern matching and/or static typing,
Harrop has a history...)

There may be synergistic benefits to pattern matching in combination
with a more powerful type system, and I wouldn't really argue against
someone claiming that the lisp type system may need some beefing up. 
But writing a standard then doing something is usually the wrong order
anyway, best implement something (probably more than once...), then
propose a standard.

But getting everyone to agree on something, especially just when you
have things like Qi coming along and demonstrating that the tradeoffs
ML and Haskell made for their type systems aren't necessarily the
tradeoffs lispers might like [1]... ouch...

[1] http://www.lambdassociates.org/advtypes.htm





















0
Reply david.golden (499) 7/24/2007 6:14:07 PM

Jon Harrop schrieb:
> David Golden wrote:
>> I don't "struggle".  I just regard it as annoying.
> 
> If you find 1+2 "annoying" then I doubt even Lisp can help.

I find it annyoing that in OCaml I have to say
(Int64.to_float (Int64.sub (Int64.mul q (Int64.of_int n)) (Int64.mul s 
s))) /. (float n)

instead of simply

[(qn - s²) / n)]

and can't something like
(when [√2 ≈ 1,41]  (print "Hello"))


André
-- 
0
Reply address.good.until.2007.dec.26 (60) 7/24/2007 6:20:29 PM

Jon Harrop schrieb:
> Andr� Thieme wrote:
>> In other situations Lisp can be the better option.
>> Joel Raymond wrote about Erlangs advantages over Haskell:
>> http://wagerlabs.com/2006/1/1/haskell-vs-erlang-reloaded/
>> For example point 3.2 was talking about static typing and the extra
>> code it needed.
> 
> Look at the vector record and zero vector definition from my ray tracer. In
> Lisp:
> 
> (defstruct (vec (:conc-name nil)
>                 (:constructor vec (x y z))
>                 (:type (vector double-float)))
>   x y z)
> 
> (defvar zero (vec 0d0 0d0 0d0))
> 
> In OCaml:
> 
> type vec = {x:float; y:float; z:float}
> let zero = {x=0.; y=0.; z=0.}


Most of what we find in here are hints for the compiler.
Also the Lisp code here is doing more than your OCaml.

(defstruct vec x y z) would have been enough if you don't want to
tell the compiler more and ask Lisp to build a constructor for you.


Andr�
-- 
0
Reply address.good.until.2007.dec.26 (60) 7/24/2007 8:37:46 PM

Joachim Durchholz <jo@durchholz.org> writes:

> Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
> most parentheses.

I wish that a blessed month could go by without somebody proposing
this.

Tamas
0
Reply tkpapp (975) 7/24/2007 8:47:09 PM

Andy Freeman schrieb:
> On Jul 24, 5:59 am, Joachim Durchholz <j...@durchholz.org> wrote:
>> Seconds, I'm saying that needing macros means that you often writen the
>> same semantics twice, once as a function and once (for those cases where
>> it's a useful optimization) as a macro.
> 
> (1) One doesn't "need" macros any more than one "needs" iteration
> statments - both are merely more convenient than the alternatives in
> certain situations.
> (2) "often"?  I almost never write something as both a macro and a
> function.  In fact, the whole point of writing something as a macro is
> usually that there's no reasonable way to write the semantics as a
> function.
> 
> For example, consider python 2.6's "with" statement.  There's no clean
> way to write it as a function, so pre 2.6 code basically repeats
> with's definition everywhere the functionality is used.

No clean way to do it in Python.
In Lisp and Haskell one could get such a "statement" in a clean way.


Andr�
-- 
0
Reply address.good.until.2007.dec.26 (60) 7/24/2007 9:01:13 PM

Paul Rubin schrieb:
> Andr� Thieme <address.good.until.2007.dec.26@justmail.de> writes:
>> In Lisp you could do the same. You could teach Lisp implicit currying
>> and also implicit lazyness (altough I think that it would feel really bad).
> 
> You can't do anything of the sort.

This is not correct.


> Consider that Haskell has no
> language support for exceptions or continuations, because they're
> implemented straightforwardly as library modules,

The same is true for Lisp. It comes with an exception system which is
programmed in Lisp. If you want you can make your own during the weekend
and others can import it as a lib. For an exception system it mostly
makes sense if everyone is using the same. I guess that Haskell could in
principle have 30 of them but probably only one is widely used.


> using a combination of lazy evaluation and currying.

In Lisp it is done with a mix of functional programming, currying,
imperative programming and some few macros.


> They can't be implemented that way in Lisp

This is not correct.
You could implement implicit currying or lazyness in Lisp and put it
online as a lib that can be loaded into a running program.
Implicit lazyness would be a tough task, nothing for 30 minutes.

Maybe in Haskell you can do the same: write a lib that when loaded will
make Haskell implicitily eager. Don't know if that is possible and if
yes how easy it would be.


Andr�
-- 
0
Reply address.good.until.2007.dec.26 (60) 7/24/2007 9:12:00 PM

Joachim Durchholz <jo@durchholz.org> writes:
> Pascal Bourguignon schrieb:
>> Joachim Durchholz <jo@durchholz.org> writes:
>>>> I have yet to see a syntax that is
>>>> both as flexible as and more concise than that of Common Lisp.
>>> Drop the superfluous parentheses, for example. A minimum amount of
>>> operator precedence and layout rules eliminates 99% of them.
>> Oops!  Now you'll have to teach this minimum amount of operator
>> precedence and layout rules to the billions of macros out there.
>
> Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
> most parentheses.

The best commentary that I ever saw on this is the following:

"Parentheses?  What parentheses? I haven't noticed any parentheses
since my first month of Lisp programming.  I like to ask people who
complain about parentheses in Lisp if they are bothered by all the
spaces between words in a newspaper..."  -- Kenny Tilton <tilt@liii.com>
-- 
(reverse (concatenate 'string "ofni.sesabatadxunil" "@" "enworbbc"))
http://cbbrowne.com/info/languages.html
"They laughed at Columbus, they laughed at Fulton, they laughed at the
Wright brothers.  But they also laughed at Bozo the Clown."
-- Carl Sagan
0
Reply cbbrowne2 (44) 7/24/2007 9:19:47 PM

[ comp.lang.lisp only
  http://www.nhplace.com/kent/PFAQ/cross-posting.html ]

Christopher Browne <cbbrowne@ca.afilias.info> writes:

> > Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
> > most parentheses.
> 
> The best commentary that I ever saw on this is the following:
> 
> "Parentheses?  What parentheses? I haven't noticed any parentheses
> since my first month of Lisp programming.  I like to ask people who
> complain about parentheses in Lisp if they are bothered by all the
> spaces between words in a newspaper..."  -- Kenny Tilton <tilt@liii.com>

Actually, although I frequently enjoy his irreverent wit, I think he's
slightly the mark on this one, since in fact all those spaces are
actually shared as token separators between CL and English text.
Perhaps periods and commas would be a closer analogy.

I started programming in FORTRAN and BASIC before I arrived at MIT, so
I could have stuck to my early upbringing and insisted on infix.  I
learned Lisp in a rapid-fire sequence of courses from Weizenbaum,
Winston, and Sussman at MIT and one of several things that attracted
me to it was its LACK of syntax.  Doing something like natural language
processing and being able to entirely leap over issues of programming 
syntax and straight to operating on end-user-intelligible data such as:

 (THIS IS SOME PROGRAM DATA THAT YOU CAN WRITE INTERESTING PROGRAMS ABOUT)

was very empowering.  Other languages generally do not allow this.
If Eliza had first been written with notations like ["THIS","IS","SOME",...]
or #{#"THIS",#"IS",...}, I very much doubt I would have found it as
compelling.

To see this notational simplicity maligned as "too complicated" leaves
me wondering whether to laugh or cry.  What is often summed up as "all
those parens" is often some distorted code for "the LACK of more
complicated syntax".  And so I just don't get it.

.... except in the case of infix math.  And it's not very hard to write
an escape syntax to get in and out of that if you need it.  It's
surely quite hard to write escape syntax to get in and out of Lisp
notation in other languages.
0
Reply pitman (1396) 7/25/2007 12:27:35 AM

"Steven E. Harris" <seh@panix.com> writes:
>> Here is a Java implementation.
>You have a truly unique style of writing and formatting your Java
>code. It took me a few moments to get accustomed to it, but it is
>readable. Aside from similarities to idiomatic Lisp, it reminds me of
>Dinkumware's style used in their C++ libraries. Take that as a
>compliment.

  Thank you! Usually I am being flamed for this style.

  I also have tried to find source code from Dinkumware.
  Found this:

http://www.dinkumware.com/manuals/images/compleat/csample.txt

  Since this post appears in comp.lang.lisp, let me mention Lisp:

  Recently someone posted:

0123456

(define (f n)
  (if (= n 0)
      1
    (* (f (1- n)) n)))

  I was baffled by the indentation: The three entries:

    - �if�,
    - �1�, and
    - �(* (f (1- n)) n)�.

  all have the same level of nesting, yet the author managed to
  give them three different indentations, at position 3, 6, and
  4, respectively.

  I try to keep it simple by always indenting by two positions
  for every level of parentheses nesting (disregarding
  semantics), so I would format this as follows.
    
0 2 4  

( define (f n)
  ( if (= n 0)
    1
    (* (f (1- n)) n)))

  (Actually I already have used a moderated version of my style
  in order not to summon too many flames).

  Readers only interested in Lisp might stop reading here.

  The flames made me write a rationale for my formating style
  I append below. I also tried to write some rules in a more
  formal way on the following page (for the language �C�).

http://www.purl.org/stefan_ram/pub/c_format_en 

  The Rationale:

  One Way to Format Parentheses

  There are several different ways to format texts with braces
  and parentheses. One of them is being described here.

  Indentation within Braces

  An indentation of just one space often is too small to be seen
  clearly, because the natural width and form of characters
  often varies by an amount that is not very much smaller than a
  space. Therefore, the indentation should amount to at least
  two positions. In order not to waste horizontal spaces, an
  indentation of exactly two positions is chosen. This means,
  that the left position of the next level is two larger than
  the position of the directly enclosing level.

  Indentation by two positions within a block

{ ++x;
  ++x; }
^ ^
0 2

  Bad A small indentation by one position is not always visible
  clearly

{++x;
 ++x; }

  Good The indentation by two positions is visible clearly

{ ++x;
  ++x; }

  Bad A large indentation by more than two positions wastes
  horizontal space with no additional benefit

{    ++x;
     ++x; }

Spaces within braces

  In mathematics, there are often no spaces at the inner side of
  parentheses or braces in expressions, but spaces are used
  indeed at the inner side of braces in set notation, when the
  braces contain a description (not when they contain a list).

  Spaces in set notation

{ x | x  > 2 }

  This style is adopted here: One space is written at the inner
  side of braces.

  Spaces at the inner side of parentheses within a block

{ ++x; }

  This style is consistent with the indentation by two
  positions, because only using this style, corresponding parts
  of two lines have the same position.

  Bad No space after the first brace, the two statements are
  misaligned

{++x;
  ++x; }

  Good One space after the first brace, the two statements are
  properly aligned

{ ++x;
  ++x; }

  Bad Two spaces after the first brace, the two statements are
  misaligned

{  ++x;
  ++x; }

  There are some exceptions to this rule: No spaces are used
  within empty braces "{}" and between two or more closing
  braces of the same direction "}}", except, when the first one
  of them is part of an empty pair "{} }" (an empty pair of
  braces if treated like a single non-braces character).

  Unified rules for all Brackets

  For simplicity and uniformity, the rules from above apply to
  all kinds of brackets, including parentheses, braces (curly
  brackets), square brackets, and angle brackets.

  Spaces within parentheses and square brackets

{ y = f( x )+ g() + a[ 2 ]; }

  Binary operators are sorrounded by a space, but the space is
  omitted, when there already is a space on the other side of a
  sequence of brackets directly beside the operator: By this rule,
  " )+" is written instead of " ) +".

  Representation of the Syntactical Structure

  A method declaration in Java consists of a head and a body.
  The following representation shows this structure:

  Good formatting according to the structure

void alpha() // head
{ beta(); }  // body

  The following formatting is misleading, because the line break
  does not match the structural break:

  Bad line break within the body

void alpha() { // head and the beginning of the body
  beta(); }    // the rest of the body

  This formatting also would make no sense for blocks within
  blocks. So it is often not used for such blocks. Therefore
  even the adopters of this style can not use it uniformly.

  Left Braces Look Like "bullets"

  There is a well known style to publish lists in typography
  using bullets sticking out on the left, looking like this:

  Common list representation with bullets in typography

o This is the first point
  of this list, it is written
  here just as an example.

o Here is another entry

o This is another example given
  just as an example to show
  an example

  The braces of the beginnings of blocks stand out on the left
  just the same, when the formatting being described here is
  used, so they look quite naturally as beginning-of-a-block
  markers, when one is used to the typographical list notation:

Left braces look like bullets to mark blocks

{ printf(); printf();
  printf(); printf(); printf();
  printf(); printf(); }

{ printf(); printf(); }

{ printf(); printf(); printf();
  printf(); printf();
  printf(); }

  Neutrality

  Someone wrote this C code:

  Code someone wrote

while( fgets( eingabe, sizeof eingabe, stdin ))
  if( sscanf( eingabe, "%d", &wert )!= 1 )
    fprintf( stderr, "Please enter a number!\n" );
  else
    summe += wert;

  It amazes me that I can add braces by my style conventions
  (not changing the meaning of the code)
  without the need to change the position of any character of
  the given code or change the overall number of line:

  The code from above plus braces

while( fgets( eingabe, sizeof eingabe, stdin ))
{ if( sscanf( eingabe, "%d", &wert )!= 1 )
  { fprintf( stderr, "Please enter a number!\n" ); }
  else
  { summe += wert; }}

  Insofar, my bracing style might be considered non-obtrusive.

0
Reply ram (2828) 7/25/2007 1:18:20 AM

On Jul 18, 9:24 am, Mark Tarver <dr.mtar...@ukonline.co.uk> wrote:
> \Jon suggested that it would be good to implement some significant
> programs in different functional languages for comparison.  He
> suggested interpreters for procedural languages like Basic.

Here is a partial solution in Haskell.  My version of Minim
is far more expressive than the original one (this comes from
free with my approach), and there is no need for an interpreter:
at run-time, the expression is "compiled" into a lambda-expression
that executes the code.  Hence, it integrates seamlessly within
the rest of Haskell.  The limitation is that everything is coded
in CPS (Continuation Passing Style) for easy use of Goto, hence
the result is somewhat slow (on my machine, 0.04 secs were necessary).
A better approach would be to replace CPS by exceptions, since a
Goto does not need to rewind ; performance should then become much
better, at the cost of purity and elegance.

data Minim r = Action (IO ())
             | Goto Tag
             | Label Tag
             | If (IO Bool) [Minim r] [Minim r]

That is, a program is either an action (embedded as a Haskell
computation in the IO monad), a Goto, a Label, or a test
(which condition is also embedded as a computation in the IO
monad).  For example,
Action (putStrLn "Add x and y") is the action that writes the
original string.  Input is done through
Action (do val <- getLine
           writeIORef x (read val))
(which sets x to an integer read on stdin).

Goto and Label are simple, and test is straightforward, too,
taking the syntax:
If (testNull varX) [Goto labEnd] [Goto labSub]
etc.

The example program can be embedded as:

bench = [ Action $ do putStrLn "Add x and y"
                      putStr "Input x: "
                      hFlush stdout
                      vx <- getLine
                      writeIORef varX (read vx)
                      putStr "Input y: "
                      hFlush stdout
                      vy <- getLine
                      writeIORef varY (read vy)
        , Label labelMain
        , If (testNull varX) [Goto labelEnd] [Goto labelSub]
        , Label labelSub
        , Action $ do modifyIORef varX (+ (-1))
        , Action $ do modifyIORef varY (+    1)
        , Goto labelMain
        , Label labelEnd
        , Action $ do putStr "The total of x and y is "
                      vy <- readIORef varY
                      print vy
                      putStrLn ""
        ]

I almost didn't cheat: transformation from an AST such as
the one used by Jon is straightforward, but I was interested
in the translation to a function part, so I will write this
part if I have time, later.

The interesting part is, of course, how this is translated
into a real Haskell function.  First, we need to define a
few types:

type Program r a = ContT r IO a
(forget the IO thing ; the meaning of that is that a program
of type a is a continuation of type a).

A tag is a reference to a program returning nothing:
type Tag = IORef (Program r ())
In other words, a Tag is nothing more than the address of the
fragment of code that corresponds to the execution of what
follows the tag in the program.

Finally, the compilation function is:
compile_: [Minim r] -> IO (Program r ())
and a cycle compile/execute is:

main = do a <- compile_ bench
          runContT a return
Please note that runContT is nothing special ; a is a "real"
Haskell lambda-expression.  It is necessary only to avoid syntax
problems.

compile_ is almost straightforward. Readers not used
to Haskell can just replace liftIO by the identity function.
I show code equivalent to the original code, but written
in a more readable fashion for non-users of Haskell.

compile_ [] = return $ liftIO (return ())
-- The empty program does nothing

compile_ (Action a : r) = do seq <- compile_ r
                             return $ do liftIO a
                                         seq

-- Interesting part:
compile_ (Label s : r) =
  do rest <- compile_ r
     liftIO (writeIORef s rest)
     return rest

compile_ (Goto p : r) =
  do compile_ r
     return $ do v <- act
                 v
  where act = liftIO $ readIORef p

------- The real compilation function ---------
compile_ [] = return (liftIO $ return ())

compile_ (Action a : r) = compile_ r >>= (\seq -> return $ liftIO a >>
seq)

compile_ (Goto p : r) = compile_ r >> (return $ (liftIO $ readIORef p)
>>= id)

compile_ (Label s : r) = compile_ r >>=
                         (\rest -> liftIO (writeIORef s rest) >>
return rest)

compile_ (If s l1 l2 : r) = compile_ r >>
    do l1' <- compile_ l1
       l2' <- compile_ l2
       return $ do v <- liftIO s
                   case v of
                     True  -> l1'
                     False -> l2'
--------------------


This approach shows:
 1- that a full-blown "pseudo-compiler" can be written
    in 13 lines of code
 2- that CPS monads in Haskell makes translation of
    spaghetti code (with gotos) almost trivial.
 3- that the interpreter itself (in Jon's solution, there
    is some structure to keep a program counter, and
    execution is performed line by line) is not necessary.
 4- that such an approach gives reasonable speed.

Of course, this is fully translatable to OCaml code.  The
only point is that since I use the ContT monad, the OCaml
code should handle continuations explicitly, which is
error-prone (but nothing the type checker cannot handle).

--
 Frederic

-- Full code begins here
-- File BMinim.hs
-- Compilation: ghc -O3 --make BMinim.hs
-- Execution: ./BMinim
-- Benchmark: exec contains twice the line "100000"
--   frederic $ time ./BMinim < exec
--   real    0m0.044s
--   user    0m0.031s
--   sys     0m0.011s

module Main
    where

import qualified Data.Map as M
import Data.Maybe
import Data.IORef
import Control.Monad.Cont

-- Only necessary for the example
import System.IO
import System.IO.Unsafe

type Program r a = ContT r IO a

type ECont r = Program r ()

type Tag r = IORef (ECont r)

data Minim r = Action (IO ())
             | Goto (Tag r)
             | Label (Tag r)
             | If (IO Bool) [Minim r] [Minim r]

compile_ :: [Minim r] -> IO (Program r ())
compile_ [] = return (liftIO $ return ())

compile_ (Action a : r) = compile_ r >>= (\seq -> return $ liftIO a >>
seq)

compile_ (Goto p : r) = compile_ r >> (return $ (liftIO $ readIORef p)
>>= id)

compile_ (Label s : r) = compile_ r >>=
                         (\rest -> liftIO (writeIORef s rest) >>
return rest)

compile_ (If s l1 l2 : r) = compile_ r >>
    do l1' <- compile_ l1
       l2' <- compile_ l2
       return $ do v <- liftIO s
                   case v of
                     True  -> l1'
                     False -> l2'


--------- Code for the example begins here -------------


labelMain :: IORef (ECont r)
labelMain = unsafePerformIO $ newIORef undefined

labelSub :: IORef (ECont r)
labelSub = unsafePerformIO $ newIORef undefined

labelEnd :: IORef (ECont r)
labelEnd = unsafePerformIO $ newIORef undefined

varX :: IORef Int
varX = unsafePerformIO $ newIORef undefined

varY :: IORef Int
varY = unsafePerformIO $ newIORef undefined

testNull :: IORef Int -> IO Bool
testNull vx = do vx' <- readIORef vx
                 return (vx' == 0)

bench = [ Action $ do putStrLn "Add x and y"
                      putStr "Input x: "
                      hFlush stdout
                      vx <- getLine
                      writeIORef varX (read vx)
                      putStr "Input y: "
                      hFlush stdout
                      vy <- getLine
                      writeIORef varY (read vy)
        , Label labelMain
        , If (testNull varX) [Goto labelEnd] [Goto labelSub]
        , Label labelSub
        , Action $ do modifyIORef varX (+ (-1))
        , Action $ do modifyIORef varY (+    1)
        , Goto labelMain
        , Label labelEnd
        , Action $ do putStr "The total of x and y is "
                      vy <- readIORef varY
                      print vy
                      putStrLn ""
        ]

main :: IO ()
main = do a <- compile_ bench
          runContT a return

0
Reply ego.frederic (3) 7/25/2007 8:05:15 AM

jayessay wrote:
> The N is not the issue - it was the missing i.

The "missing i" makes no difference so you might as well not write it.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 8:20:29 AM

Andr� Thieme wrote:
> Most of what we find in here are hints for the compiler.
> Also the Lisp code here is doing more than your OCaml.
> 
> (defstruct vec x y z) would have been enough if you don't want to
> tell the compiler more and ask Lisp to build a constructor for you.

You have literals in OCaml.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 8:21:50 AM

David Golden wrote:
> There may be synergistic benefits to pattern matching in combination
> with a more powerful type system, and I wouldn't really argue against
> someone claiming that the lisp type system may need some beefing up.

The pattern matching in Haskell and ML swings on closed sum types which,
AFAIK, don't exist in Lisp. This is the main reason why ML-style pattern
matching isn't useful in Lisp.

> But writing a standard then doing something is usually the wrong order
> anyway, best implement something (probably more than once...), then
> propose a standard.
> 
> But getting everyone to agree on something, especially just when you
> have things like Qi coming along and demonstrating that the tradeoffs
> ML and Haskell made for their type systems aren't necessarily the
> tradeoffs lispers might like [1]... ouch...

You might want C++'s type system, yes.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 8:29:13 AM

Tamas Papp wrote:
> Joachim Durchholz <jo@durchholz.org> writes:
>> Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
>> most parentheses.
> 
> I wish that a blessed month could go by without somebody proposing
> this.

Amen to that. You might as well go back to caveman and propose fire...

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 8:30:42 AM

Andr� Thieme wrote:
> Jon Harrop schrieb:
>> David Golden wrote:
>>> I don't "struggle".  I just regard it as annoying.
>> 
>> If you find 1+2 "annoying" then I doubt even Lisp can help.
> 
> I find it annyoing that in OCaml I have to say
> (Int64.to_float (Int64.sub (Int64.mul q (Int64.of_int n)) (Int64.mul s
> s))) /. (float n)

You can remove some parentheses and open the Int64 module to simplify it a
bit:

# open Int64;;
# let f q n s = to_float(sub (mul q (of_int n)) (mul s s)) /. float n;;
val f : int64 -> int -> int64 -> float = <fun>

Also, you can define or override infix operators locally or create new
operators:

# let f q n s =
    let ( - ) = sub and ( * ) = mul in
    to_float(q * of_int n - s * s) /. float n;;
val f : int64 -> int -> int64 -> float = <fun>

> instead of simply
> 
> [(qn - s�) / n)]

You can certainly write a macro that implements that syntax but the
resulting code would not be efficient as there is no static type
information.

In this particular case, are you sure you can't just use floats throughout?

> and can't something like
> (when [?2 ? 1,41]  (print "Hello"))

You can define a =~ operator:

# let ( =~ ) x y = abs_float(x -. y) < sqrt epsilon_float;;
val ( =~ ) : float -> float -> bool = <fun>

and use it in the guard of a pattern match:

# match sqrt 2., 1.414213562 with
  | x, y when x =~ y -> "Similar"
  | _ -> "Dissimilar";;
- : string = "Similar"

However, approximate equality on floats is discouraged in any language. I
would recommend interval arithmetic instead.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 8:57:02 AM

This is very interesting, thank you.

Frederic wrote:
> ...
> Hence, it integrates seamlessly within 
> the rest of Haskell.  The limitation is that everything is coded
> in CPS (Continuation Passing Style) for easy use of Goto, hence
> the result is somewhat slow (on my machine, 0.04 secs were necessary).
> A better approach would be to replace CPS by exceptions, since a
> Goto does not need to rewind ; performance should then become much
> better, at the cost of purity and elegance.

I don't follow this. How can you replace CPS with exceptions?

> I almost didn't cheat: transformation from an AST such as
> the one used by Jon is straightforward, but I was interested
> in the translation to a function part, so I will write this
> part if I have time, later.

I would very much like to see parsers written in Haskell and Lisp. Also,
note that I omitted the superfluous parentheses from the Minim language in
my parser: the program I'm evaluating contains no brackets.

> This approach shows:
>  1- that a full-blown "pseudo-compiler" can be written
>     in 13 lines of code

I am not sure what the meaning of "pseudo-compiler" is. I would call this an
interpreter that composes functional rather than non-functional values. In
both cases, you can obtain a closure that, when invoked, evaluates a
program. In both cases, performance will be comparable (i.e. neither can
approach the performance of a real compiler like Pascal's).

So I cannot see any difference between this and an ordinary interpreter,
except that an ordinary interpreter has an intermediate representation that
can be visualized whereas a monadic interpreter has a network of closures
that cannot be examined so easily.

>  2- that CPS monads in Haskell makes translation of
>     spaghetti code (with gotos) almost trivial.

Pascal used a similar trick in his Lisp. I never got around to implementing
this in OCaml or MetaOCaml.

However, saying that CPS makes something almost trivial is only useful as a
comparison. In this case, I would say that CPS is significantly more
complicated than iterating a program counter.

>  3- that the interpreter itself (in Jon's solution, there
>     is some structure to keep a program counter, and
>     execution is performed line by line) is not necessary.

Yes. I believe you have traded an explicit program counter for impicit
invocation of continuations. AFAICT, the main advantage of using CPS here
is that it allows you to stage evaluation as Pascal did. This was noted by
the MetaOCaml team in their published literature as well.

So I shall have to transform my interpreter into the CPS/Monadic form before
I can stage it in MetaOCaml. I think the results will be very
interesting... :-)

>  4- that such an approach gives reasonable speed.
> 
> Of course, this is fully translatable to OCaml code.  The
> only point is that since I use the ContT monad, the OCaml
> code should handle continuations explicitly, which is
> error-prone (but nothing the type checker cannot handle).

I suspect the ContT monad can even be expressed in OCaml's type system so
you could easily write in a monadic style in OCaml in this case. Monads
seem like overkill for a 50-line program though. :-)

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 10:16:16 AM

Markus E Leypold wrote:
> Rule of thumb for me: The larger the scope the more descriptive the
> variable name should be. Actually modify that by how far away the
> corresponding type definitions have been made:
> 
>   let f l = ...  (* bad *)
> 
>   let f customer_list = ... (* better *)
> 
>   let f (customers : customer list) = ...  (* best *)

Yes. I agree in spirit: longer-lived values deserve more descriptive names
in any language.

> But
> 
>   let f (customers ...) =
> 
>      ...
> 
>      let process cs ... =
>          ...
> 
>      in
> 
>          process customers ... ;;
> 
> because all information is there locally to derive what 'cs' is.

This might be considered bad style in ML where it is preferable to write
many small, separate functions rather than nesting definitions. Hiding is
provided by module signatures.

For example, the "length" function from the OCaml standard library:

let rec length_aux len = function
    [] -> len
  | a::l -> length_aux (len + 1) l

let length l = length_aux 0 l

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 10:23:04 AM

Pascal Bourguignon schrieb:
> Joachim Durchholz <jo@durchholz.org> writes:
> 
>> Pascal Bourguignon schrieb:
>>> Joachim Durchholz <jo@durchholz.org> writes:
>>>>> I have yet to see a syntax that is
>>>>> both as flexible as and more concise than that of Common Lisp.
>>>> Drop the superfluous parentheses, for example. A minimum amount of
>>>> operator precedence and layout rules eliminates 99% of them.
>>> Oops!  Now you'll have to teach this minimum amount of operator
>>> precedence and layout rules to the billions of macros out there.
>> Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
>> most parentheses.
> 
> Like in:
> 
>   #define a(x,y) x*y
> 
> perhaps?

If you really thought I were advocating C macros, you should seriously 
consider getting professional help.

> To be able to use this macro as:
> 
>   (int)a(1.0+2.0,3.0+4.0)
> 
> you need to actually define it as:
> 
>   #define a(x,y) ((x)*(y))
> 
> so much for operator precedence and layout rules.

Strawman argument.

First, I've been talking about precedences in functions, not in macros. 
(The only language that I know where this kind of problem arises even in 
functions is Tcl. Guess which language I'll refuse to program in.)

Second, the C preprocessor does substitution at the character level 
(sometimes at the token level if it's more recent than K&R C). That's a 
far cry from modern preprocessing which does the substitutions at the 
AST level, where this kind of problem doesn't arise in the first place.

> In lisp, you merely write it as:
> 
>   (defmacro a (x y) `(* ,x ,y))
> 
> less parentheses than in C!

Suggesting pro-C advocacy is considered a serious offense here in 
comp.lang.functional, you know ;-)

Regards,
jo
0
Reply jo427 (1164) 7/25/2007 11:10:56 AM

Andr� Thieme schrieb:
> 
> The same is true for Lisp. It comes with an exception system which is
> programmed in Lisp. If you want you can make your own during the weekend
> and others can import it as a lib.

Hm... I think that weekend would be just the programming.
Designing an exception system well requires a great deal of experience.

 > For an exception system it mostly
> makes sense if everyone is using the same. I guess that Haskell could in
> principle have 30 of them but probably only one is widely used.

Confirm.

> This is not correct.
> You could implement implicit currying or lazyness in Lisp and put it
> online as a lib that can be loaded into a running program.
> Implicit lazyness would be a tough task, nothing for 30 minutes.

In any language where that is possible at all.
Implicit laziness requires a great deal of support from the run-time 
system to get even near acceptable performance. I don't think that Lisp 
could do that; you'd essentially end up reimplementing Haskell in Lisp 
(or a lazy Lisp in Lisp).

> Maybe in Haskell you can do the same: write a lib that when loaded will
> make Haskell implicitily eager. Don't know if that is possible and if
> yes how easy it would be.

No, that's not possible.

You can't look "under the hood of the implementation" in Haskell as you 
would in Lisp.

Novices often try to achieve efficiency by forcing expressions into 
eager evaluation. Most fail, because the eagerness operators in Haskell 
are nontrivial to use; even those who succeed have rather ugly code and 
drop the practice quickly.
OTOH there are other optimization techniques that work well. 
(Memoization is a popular alternative and does not require you to hash 
your code up.)
Leaving optimization and debugging purposes aside, I haven't seen 
anybody wanting eager evaluation in Haskell in years, not even in 
specific situations and most certainly not as a by-default strategy. (I 
believe the latter is more because those who find lazy evaluation 
utterly unpalatable don't use Haskell for long.)

Regards,
Jo
0
Reply jo427 (1164) 7/25/2007 11:27:43 AM

On 2007-07-25, Jon Harrop <jon@ffconsultancy.com> wrote:
>> Hence, it integrates seamlessly within 
>> the rest of Haskell.  The limitation is that everything is coded
>> in CPS (Continuation Passing Style) for easy use of Goto, hence
>> the result is somewhat slow (on my machine, 0.04 secs were necessary).
>> A better approach would be to replace CPS by exceptions, since a
>> Goto does not need to rewind ; performance should then become much
>> better, at the cost of purity and elegance.
>
> I don't follow this. How can you replace CPS with exceptions?

The reason why the Cont monad is needed is that Gotos break explicitely
the flow.  My current solution is to explicitely set the continuation.
Another solution would be that a goto throws an exception containing
the pointer to the new function to be evaluated, and that the 
exception handler just runs the obtained code.  

>> This approach shows:
>>  1- that a full-blown "pseudo-compiler" can be written
>>     in 13 lines of code
>
> I am not sure what the meaning of "pseudo-compiler" is. I would call this an
> interpreter that composes functional rather than non-functional values. In
> both cases, you can obtain a closure that, when invoked, evaluates a
> program. In both cases, performance will be comparable (i.e. neither can
> approach the performance of a real compiler like Pascal's).

You're right ; "pseudo-compiler" is not the right word.  The difference
between what I do and an interpreter is that, when interpreting, translation
of an instruction is performed many times.
In my example, translation is performed only once.

> So I cannot see any difference between this and an ordinary interpreter,
> except that an ordinary interpreter has an intermediate representation that
> can be visualized whereas a monadic interpreter has a network of closures
> that cannot be examined so easily.

Note that it's not the point that it is monadic - this is Haskell, so
it is monadic, but with exceptions in OCaml, you wouldn't need monads.

>>  2- that CPS monads in Haskell makes translation of
>>     spaghetti code (with gotos) almost trivial.
>
> Pascal used a similar trick in his Lisp. I never got around to implementing
> this in OCaml or MetaOCaml.

I have a working but partial version in Template Haskell.  I will post
and discuss when it is complete.

-- 
 Frederic
0
Reply ego.frederic (3) 7/25/2007 11:30:42 AM

Joachim Durchholz <jo@durchholz.org> writes:

> Pascal Bourguignon schrieb:
>> Joachim Durchholz <jo@durchholz.org> writes:
>>
>>> Pascal Bourguignon schrieb:
>>>> Joachim Durchholz <jo@durchholz.org> writes:
>>>>>> I have yet to see a syntax that is
>>>>>> both as flexible as and more concise than that of Common Lisp.
>>>>> Drop the superfluous parentheses, for example. A minimum amount of
>>>>> operator precedence and layout rules eliminates 99% of them.
>>>> Oops!  Now you'll have to teach this minimum amount of operator
>>>> precedence and layout rules to the billions of macros out there.
>>> Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
>>> most parentheses.
>>
>> Like in:
>>
>>   #define a(x,y) x*y
>>
>> perhaps?
>
> If you really thought I were advocating C macros, you should seriously
> consider getting professional help.

Neither did I think that, neither did I advocate anything.  I only too
C as an example of a language with "A minimum amount of operator
precedence and layout rules to eliminate 99% of them [parentheses]."


>> To be able to use this macro as:
>>
>>   (int)a(1.0+2.0,3.0+4.0)
>>
>> you need to actually define it as:
>>
>>   #define a(x,y) ((x)*(y))
>>
>> so much for operator precedence and layout rules.
>
> Strawman argument.
>
> First, I've been talking about precedences in functions, not in
> macros. (The only language that I know where this kind of problem
> arises even in functions is Tcl. Guess which language I'll refuse to
> program in.)

This is irrelevant.


> Second, the C preprocessor does substitution at the character level
> (sometimes at the token level if it's more recent than K&R C). 

This is irrelevant.


> That's a far cry from modern preprocessing which does the
> substitutions at the AST level, where this kind of problem doesn't
> arise in the first place.

That's my point!  There is NO parenthesis in lisp!
To wit:

* (dump-thing '(defun dump-thing (thing &optional (level 0))
                (if (atom thing)
                    (format t "~VA An atom: ~S~%" level "" thing)
                    (progn
                      (format t "~VA A cons cell:~%" level "")
                      (dump-thing (car thing) (1+ level))
                      (dump-thing (cdr thing) (1+ level))))))
 A cons cell:
  An atom: DEFUN
  A cons cell:
   An atom: DUMP-THING
   A cons cell:
    A cons cell:
     An atom: THING
     A cons cell:
      An atom: &OPTIONAL
      A cons cell:
       A cons cell:
        An atom: LEVEL
        A cons cell:
         An atom: 0
         An atom: NIL
       An atom: NIL
    A cons cell:
     A cons cell:
      An atom: IF
p      A cons cell:
       A cons cell:
        An atom: ATOM
        A cons cell:
         An atom: THING
         An atom: NIL
       A cons cell:
        A cons cell:
         An atom: FORMAT
         A cons cell:
          An atom: T
          A cons cell:
           An atom: "~VA An atom: ~S~%"
           A cons cell:
            An atom: LEVEL
            A cons cell:
             An atom: ""
             A cons cell:
              An atom: THING
              An atom: NIL
        A cons cell:
         A cons cell:
          An atom: PROGN
          A cons cell:
           A cons cell:
            An atom: FORMAT
            A cons cell:
             An atom: T
             A cons cell:
              An atom: "~VA A cons cell:~%"
              A cons cell:
               An atom: LEVEL
               A cons cell:
                An atom: ""
                An atom: NIL
           A cons cell:
            A cons cell:
             An atom: DUMP-THING
             A cons cell:
              A cons cell:
               An atom: CAR
               A cons cell:
                An atom: THING
                An atom: NIL
              A cons cell:
               A cons cell:
                An atom: 1+
                A cons cell:
                 An atom: LEVEL
                 An atom: NIL
               An atom: NIL
            A cons cell:
             A cons cell:
              An atom: DUMP-THING
              A cons cell:
               A cons cell:
                An atom: CDR
                A cons cell:
                 An atom: THING
                 An atom: NIL
               A cons cell:
                A cons cell:
                 An atom: 1+
                 A cons cell:
                  An atom: LEVEL
                  An atom: NIL
                An atom: NIL
             An atom: NIL
         An atom: NIL
     An atom: NIL
NIL
* 


See?  Absolutely NO parenthesis can be dumped.       


>> In lisp, you merely write it as:
>>
>>   (defmacro a (x y) `(* ,x ,y))
>>
>> less parentheses than in C!
>
> Suggesting pro-C advocacy is considered a serious offense here in
> comp.lang.functional, you know ;-)

This was anti C, as an example of anti-what you get when you add "A
minimum amount of operator precedence and layout rules [to] eliminate
99% of them [parentheses]."



Perhaps you should try to explicit your "few hard-and-fast rules"...

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

This universe shipped by weight, not volume.  Some expansion may have
occurred during shipment.
0
Reply pjb (7647) 7/25/2007 12:05:16 PM

> The pattern matching in Haskell and ML swings on closed sum types
> which, AFAIK, don't exist in Lisp. This is the main reason why
> ML-style pattern matching isn't useful in Lisp. 

No shit (though there are techniques that come closer than things we've
seen here. No, I really can't be bothered going into more detail)

While it turns out a post [1] where I touch on that is invisible in
google groups due to some sort of hole in google's memory around the
17th, so charitably I guess you might have missed it too in whatever
the screw-up was, I had assumed you knew I and others knew that and
were just being your usual obnoxious self with later replies to certain
other posts, in keeping with a probable strategy to prolong threads and
afford more opportunities to spam.

> You might want C++'s type system, yes.

Qi's type system is turing-complete, yes. However, to assert it's the
therefore "the same" as the twisted horror of C++ would be silly.  I
assume you're not doing that.

[1]
http://coding.derkeiler.com/Archive/Lisp/comp.lang.lisp/2007-07/msg01113.html



0
Reply david.golden (499) 7/25/2007 12:33:55 PM

On Jul 24, 10:47 pm, Tamas Papp <tkp...@gmail.com> wrote:
> Joachim Durchholz <j...@durchholz.org> writes:
> > Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
> > most parentheses.
>
> I wish that a blessed month could go by without somebody proposing
> this.
>
> Tamas

That's a definitely bad, as it would mean there's nobody who's
starting to learn  lisp. Some of them will whine and leave, the rest
will stay.

Why do you prefer lisp over Ocaml/F# ?
I would rather been called a savage than a spammer.


0
Reply slobodan.blazeski (1459) 7/25/2007 12:49:42 PM

Hi,


> > First of all, INCF is a macro.
>
> That's why I wrote "syntactic equivalent".
> I was all talking about the overhead of having parentheses.

Well, what I was trying to say was that the given pieces of code were
_not_ syntactically equivalent, because in Lisp, INCF is a part of the
syntax, whereas in Haskell, it is not.


>  > How do you curry a macro?  That doesn't make much sense to me.
>
> I don't see any problems applying currying to macros that wouldn't apply
> to functions, or vice versa.

Hmm.  Maybe you're right about that.  I will have to think about this
a bit.


> > Second, INCF takes a place as its first argument, not a value.
>
> Seems like a macro thing to me.

Yes, that's the point.  In other languages, you would need an
additional syntactic device to distinguish places from values.  As
INCF defines its own syntax, that is not necessary in Lisp.


> There is no difference between a macro and a function in Haskell.
>
> In Haskell, there is no semantic difference between compile-time and
> run-time evaluation, so any macro would be a function and vice versa.

Macros are different from functions not only in their time of
evaluation, but also in their semantics.  Their purpose is not
precomputing stuff at compile-time, but the definition of new syntax
and transformation of code.

Doing evaluation prior to run-time can be done without macros.  That's
what compiler macros, EVAL-WHEN and LOAD-TIME-VALUE are for (among
others).  (Yeah, the terminology is confusing.  Macros, reader macros
and compiler macros are all different things.)  Also note that some
Lisp interpreters (rather than compilers) do macroexpansion at run-
time, so the reverse is true as well.


> You *can* have macros in Haskell (just plop in a preprocessor), but they
> aren't nearly as pressingly needed as in an impure language. (That may
> be the reason why preprocessors are more en vogue for OCaml than for
> Haskell.)

That may be one reason.  Another reason may be the higher complexity
and intrusiveness of macros in a language with complex syntax.  We can
only guess here.


> Drop the superfluous parentheses, for example. A minimum amount of
> operator precedence and layout rules eliminates 99% of them.
> That's "just lexical conciseness", you'll say, and you'd be correct.
> However, when I look at the sheer percentage of screen estate these
> parentheses are taking up, it's getting too much.

Oh yes, lexical conciseness is a form of conciseness all right.  I'd
love to see the syntax you're thinking of.

Mata ne,
Matthias

0
Reply mulkiatsch (106) 7/25/2007 12:54:06 PM

Bah. Answering is pointless if the other person just redefines the topic 
to make a point.
0
Reply jo427 (1164) 7/25/2007 1:26:32 PM

> What clued us in was the use of diminuitive names (Jonnie boy) for
> your opponent 

http://xkcd.com/291/




















0
Reply david.golden (499) 7/25/2007 1:31:51 PM

Matthias Benkard schrieb:
> Hi,
> 
> 
>>> First of all, INCF is a macro.
>> That's why I wrote "syntactic equivalent".
>> I was all talking about the overhead of having parentheses.
> 
> Well, what I was trying to say was that the given pieces of code were
> _not_ syntactically equivalent, because in Lisp, INCF is a part of the
> syntax, whereas in Haskell, it is not.

Heck, this entire subthread is about syntax and parentheses.
I don't get why people insist on changing the subject to to pick a nit.

I'm well aware that macros are a different concept than functions.

But that's not what I'm talking about; all I want to say is that Lisp's 
insistence on not having operator precedence comes at the price of 
having to write lots of parentheses when entering code. And that these 
parentheses, tiny as they are in isolation, take up a good deal of 
screen space because there are so many of them.

If I were talking about semantic differences, I'd have said that the 
difference between macros and functions vanishes in pure languages, so 
you can leave it to the compiler do decide what to consider a macro and 
what to consider a function.
I'd also have pointed out that the various quoting mechanisms are 
superfluous in Haskell; the subtle semantic differences between quoting 
mechanisms is what keeps me from using Lisp. (And possibly others, too; 
learning the differences is hard, and applying the right quoting 
mechanism and the right level of quoting can be difficult unless you 
know exactly what you're doing - there's a rather steep learning curve 
in that particular area of Lisp, an area that doesn't even exist in most 
other languages.)

>>> Second, INCF takes a place as its first argument, not a value.
>> Seems like a macro thing to me.
> 
> Yes, that's the point.  In other languages, you would need an
> additional syntactic device to distinguish places from values.  As
> INCF defines its own syntax, that is not necessary in Lisp.

What, then, is a place?

>> There is no difference between a macro and a function in Haskell.
>>
>> In Haskell, there is no semantic difference between compile-time and
>> run-time evaluation, so any macro would be a function and vice versa.
> 
> Macros are different from functions not only in their time of
> evaluation, but also in their semantics.  Their purpose is not
> precomputing stuff at compile-time, but the definition of new syntax
> and transformation of code.

Code transformation is done by the compiler in Haskell.
Abstraction (i.e. new languages) is daily staple in Haskell. Sure, 
Haskell embedded languages cannot do fancy syntax, but if you're fine 
with frugal syntax, you define your embedded language simply as a set of 
HOFs to use.
All without macros...

>> You *can* have macros in Haskell (just plop in a preprocessor), but they
>> aren't nearly as pressingly needed as in an impure language. (That may
>> be the reason why preprocessors are more en vogue for OCaml than for
>> Haskell.)
> 
> That may be one reason.  Another reason may be the higher complexity
> and intrusiveness of macros in a language with complex syntax.

Seems reasonable.

>> Drop the superfluous parentheses, for example. A minimum amount of
>> operator precedence and layout rules eliminates 99% of them.
>> That's "just lexical conciseness", you'll say, and you'd be correct.
>> However, when I look at the sheer percentage of screen estate these
>> parentheses are taking up, it's getting too much.
> 
> Oh yes, lexical conciseness is a form of conciseness all right.  I'd
> love to see the syntax you're thinking of.

Hmm... I think I already outlined it elsewhere.

Anyway, here goes:

First, a predefined set of operator precedences. Precedence levels would 
be the usual suspects:

Binding =
Boolean Additive |
Boolean Multiplicative &
Comparison < = > <= >= !=
Arithmetic Additive + -
Arithmetic Multiplicative * /

Throw in an "indendation is another way to write parentheses" rule.

Stick with parentheses otherwise.

Creating new precedence levels should be possible, but be a rare exception.

This is just a rough sketch.
The point of the indentation rule is that you can freely trade 
horizontal and vertical space. And you don't need closing parentheses 
anymore (I think humans concentrate on the beginning of a parentheseized 
expression, the ends are curiously uninteresting - and indentation rules 
are asymmetric, inverting the lines of a structurally indented program 
is not the same as inverting the order of symbols in parenthesized 
expressions).

Regards,
Jo
0
Reply jo427 (1164) 7/25/2007 1:49:54 PM

>> What clued us in was the use of diminuitive names (Jonnie boy) for
>> your opponent 
>
> http://xkcd.com/291/

And that tells us what, "Golden Boy Davy"? That there dignity is
presumptous? That you can people call what you like w/o that
reflecting back on you? That cupping your ears with your hands and
being insulting is mature behaviour?

Whatever -- I'm still missing any arguments on your side, but please
don't revive Davy Golden vs. Jon Harrop: It's not so interesting and
you're fighting hill upwards since you already got identified as
troll.

Good bye -- Markus



0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/25/2007 2:24:32 PM

On 2007-07-25, Frederic <ego.frederic@gmail.com> wrote:
> On Jul 18, 9:24 am, Mark Tarver <dr.mtar...@ukonline.co.uk> wrote:
>> \Jon suggested that it would be good to implement some significant
>> programs in different functional languages for comparison.  He
>> suggested interpreters for procedural languages like Basic.
>
> Here is a partial solution in Haskell.  My version of Minim
> is far more expressive than the original one (this comes from
> free with my approach), and there is no need for an interpreter:
> at run-time, the expression is "compiled" into a lambda-expression
> that executes the code.  Hence, it integrates seamlessly within
> the rest of Haskell.  The limitation is that everything is coded
> in CPS (Continuation Passing Style) for easy use of Goto, hence
> the result is somewhat slow (on my machine, 0.04 secs were necessary).
> A better approach would be to replace CPS by exceptions, since a
> Goto does not need to rewind ; performance should then become much
> better, at the cost of purity and elegance.

Now for a very efficient but not so elegant solution : I am
asking template Haskell to 
 1) write a program in C corresponding to the minim program
 2) compile it into a shared library
 3) generate binding to load and execute it at execution time.

I do not post execution time, since it is essentially the same as
a compiled C program.  Here is an example of use:

------------------------------------------------------------------------------
-- File Main.hs
-- Compilation: ghc -fth -fglasgow-exts --make Main.hs
-- In the interpreter: ghci -fth -fglasgow-exts is required
module Main
    where

import CLink
import System.Posix.DynamicLinker 

main :: IO ()
main = $(minimC "foo"
         [ PutL "Add x and y\n"
         , PutL "x = ? "
         , Input "x"
         , PutL "y = ? "
         , Input "y"
         , Label "main"
         , If (Equal 0 "x") (Goto "end") (Goto "loop")
         , Label "loop"
         , Incr "x" (-1)
         , Incr "y" 1
         , Goto "main"
         , Label "end"
         , Output "y"
         , PutL "\n" ]) 
------------------------------------------------------------------------------

The CLink module requires gcc and libtool to be installed.  This runs
on my MacBookPro ; your mileage may vary, and you'll possibly have to
modify the calls to the gcc toolchain.  But as proof-of-concept, it works
just fine.

The process is extremely similar to what Kyoto Lisp (now GCL) does, and
performance is same as C (for obvious reasons).  The front-end is 
almost seamless, though the implementation is ugly and unreliable (well,
pay me consultant fees and I will do better :) ).

-- 
 Frederic


module CLink
    where

import qualified Data.Set as S
import System.IO
import System.Posix.DynamicLinker
import System.Posix.Temp
import System.Process
import Language.Haskell.TH
import Foreign.C
import Foreign.Ptr

type IntF = CInt -> IO ()
foreign import ccall "dynamic" mkFun :: FunPtr IntF -> IntF

decl :: Dec
decl = ForeignD (ImportF CCall 
                         Unsafe 
                         "run" 
                         (mkName "foo")
                         (AppT (ConT (mkName "IO")) (TupleT 0)))


data Test = Equal Int String 
instance Show Test
    where
       show (Equal i s) = (show i) ++ "==" ++ s

varsT (Equal _ s) = S.singleton s

data Prog = Incr String Int
          | Label String
          | Goto String
          | If Test Prog Prog
          | PutL String
          | Input String
          | Output String
          | Group [String] [Prog]

(<+>) = S.union 

vars (Incr s _) = S.singleton s
vars (If t p1 p2) = varsT t <+> vars p1 <+> vars p2
vars (Input s) = S.singleton s
vars (Output s) = S.singleton s
vars (Group v p) = (S.fromList v) <+> (S.unions (map vars p))
vars _ = S.empty

instance Show Prog
    where
      show (Incr a n) = "  " ++ a ++ "+=" ++ (show n) ++ ";\n"
      show (Input s)  = "  scanf(\"%i\", &" ++ s ++ ");\n"
      show (PutL s)   = "  printf(\"%s\", " ++ (show s) ++ ");\n"
      show (Goto s)   = "  goto " ++ s ++ ";\n"
      show (Label s)  = s ++ ":\n"
      show (Output s) = "  printf(\"%i\", " ++ s ++ ");\n"
      show (Group [] p)  = "{" ++ (concat (map show p)) ++ "}"
      show (Group [v] p) = "{ int " ++ v ++ ";\n" ++ (concat (map show p)) ++ "}"
      show (Group (t : q) p) = "{ int " ++ t ++ (concat (map (", "++) q))
                               ++ ";\n" ++ (concat (map show p)) ++ "}"
      show (If t b1 b2) = "  if(" ++ (show t) ++ ")" ++ (show b1) ++ "  else" ++ (show b2)



compileAs :: String -> [Prog] -> String
compileAs name p = "#include <stdio.h>\n\nvoid " ++ 
                   name ++ "(int fooqux)\n" ++ (show gp)
  where
    gp = Group vs p
    vs = S.toList (S.unions $ map vars p)

    run n p = do let nn = "qubar_" ++ n
                 putStrLn $ nn ++ ".c"
                            (n, h) <- mkstemp $ nn ++ ".c"
                            hPutStrLn h (compileAs nn p)
                            hClose h
                            (runCommand $ "gcc -c " ++ nn ++ ".c") >>= waitForProcess
                            (runCommand $ "libtool -dynamic " ++ nn 
                               ++ ".o -lc -o lib" ++ nn ++ ".dylib") >>= waitForProcess
                            runCommand $ "rm " ++ nn ++ ".c"
                            return (nn, "lib" ++ nn ++ ".dylib")

type IOFI = IO (FunPtr IntF)

minimC :: String -> [Prog] -> Q Exp
nWDL  = VarE $ mkName "withDL"
nDLS  = VarE $ mkName "dlsym"
nIOFI = ConT $ mkName "IOFI"

minimC n p = do (obj, lib) <- runIO (run n p)
                return (AppE (AppE (AppE nWDL (LitE $ StringL lib))
                                                   (ListE []))
                                        (lam obj))

  where
    lam o   = LamE [VarP (mkName "dl")] (prog o)
    prog o  = DoE [ s1 o, s2 ]
    s1 o    = BindS (VarP (mkName "kas")) (call1 o)
    call1 o = AppE (AppE nDLS (VarE $ mkName "dl")) (LitE $ StringL o)
    s2      = NoBindS call2
    call2   = AppE (AppE (VarE $ mkName "mkFun") (VarE $ mkName "kas"))
                     (LitE $ IntegerL 42)

0
Reply ego.frederic (3) 7/25/2007 3:04:20 PM

Andr� Thieme <address.good.until.2007.dec.26@justmail.de> writes:
> The same is true for Lisp. It comes with an exception system which is
> programmed in Lisp. If you want you can make your own during the weekend
> and others can import it as a lib. 

But I don't think this is possible, unless I'm missing something.  I
mean, you could write the Lisp condition system as a macro library,
but down at the bottom the library would have to use a
language-supported primitive like catch/throw or something, to
interrupt the flow of control.  What I'm getting at is that Haskell
doesn't need such a primitive because the ability to steer the flow of
control arises automatically from lazy evaluation.

Thanks to Neel re clarification about continuations.
0
Reply phr.cx (5483) 7/25/2007 3:41:47 PM

Slobodan Blazeski <slobodan.blazeski@gmail.com> writes:

> On Jul 24, 10:47 pm, Tamas Papp <tkp...@gmail.com> wrote:
>> Joachim Durchholz <j...@durchholz.org> writes:
>> > Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
>> > most parentheses.
>>
>> I wish that a blessed month could go by without somebody proposing
>> this.
>>
>> Tamas
>
> That's a definitely bad, as it would mean there's nobody who's
> starting to learn  lisp. Some of them will whine and leave, the rest
> will stay.

I don't think that people who seriously want to learn Lisp go through
the whine-about-parenthesis stage.  Anyone with at least a nontrivial
interest in Lisp will read the first few chapters of a Lisp book, and
by that time, they will see the light.

My impression is that people who whine about parens have heard about
how good Lisp is, didn't get it and started to complain about
something trivial, or have been forced to learn some very basic Lisp
in a bad college course and resent that.

> Why do you prefer lisp over Ocaml/F# ?

Fortunately, my acquaintance with Ocaml/F# is cursory, I have looked
at Ocaml once and decided that it is not for me.  I tried Haskell last
summer, but for the stuff I am doing (numerical analysis) lazy
evaluation is not practical.  Lisp was almost perfect from the first
moment, even before I learned about macros.

> I would rather been called a savage than a spammer.

?

Tamas
0
Reply tkpapp (975) 7/25/2007 4:28:19 PM

Joachim Durchholz wrote:

> What, then, is a place?
> 
http://www.lisp.org/HyperSpec/Body/sec_5-1-1.html

By example - "increment the second element of the array
that is in b in an instance of structure s that is bound to a":
(incf (aref (s-b a) 1))

Perhaps not so relevant in a non-mutable/non-side-effecting context: The
primary purpose of the above incf form is presumably to mutate, though
it will return a value too.  


0
Reply david.golden (499) 7/25/2007 5:29:52 PM

Pascal Bourguignon wrote:
> There is NO parenthesis in lisp!
> 
> * (dump-thing '(defun dump-thing (thing &optional (level 0))
>                 (if (atom thing)
>                     (format t "~VA An atom: ~S~%" level "" thing)
>                     (progn
>                       (format t "~VA A cons cell:~%" level "")
>                       (dump-thing (car thing) (1+ level))
>                       (dump-thing (cdr thing) (1+ level))))))

I think that example was suboptimal... :-)

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 6:10:23 PM

David Golden wrote:
>> You might want C++'s type system, yes.
> 
> Qi's type system is turing-complete, yes. However, to assert it's the
> therefore "the same" as the twisted horror of C++ would be silly.  I
> assume you're not doing that.

That's exactly what I'm doing. If you want to know why undecideability is
bad, read the literature on ML (it'll be in the history section now).

Qi has the world's most powerful type system. So does C++...

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 6:19:41 PM

Joachim Durchholz wrote:
> In any language where that is possible at all.
> Implicit laziness requires a great deal of support from the run-time
> system to get even near acceptable performance. I don't think that Lisp
> could do that; you'd essentially end up reimplementing Haskell in Lisp
> (or a lazy Lisp in Lisp).

Exactly.

> Leaving optimization and debugging purposes aside, I haven't seen
> anybody wanting eager evaluation in Haskell in years, not even in
> specific situations and most certainly not as a by-default strategy.

I lurk on the Haskell Cafe mailing list and eager evaluation is often the
solution to reliability or performance problems: laziness is unpredictable.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 6:19:58 PM

> That's exactly what I'm doing.

Well, that is silly.  Didn't we hear enough of that in... 2005?
http://www.lambdassociates.org/studies/study03.htm


0
Reply david.golden (499) 7/25/2007 7:05:04 PM

Markus E Leypold wrote:

>> http://xkcd.com/291/
> 
> And that tells us what, "Golden Boy Davy"? 

That was directed more at *your* ridiculous levels of outrage at minor
childishness (at least interpreting your reaction naively, I could be
more charitable and assume Germans find name diminution and/or
childishness in general peculiarly offensive compared to English or
Irish people. Neoteny being a defining characteristic of our species,
I'd recommend not being so down on childishness). 

I'd expect Jon to be roughly as insulted by Jonnie Boy as I would be by
Golden Boy. That is to say, very, very mildly. If anything, such
devices are usually used to soften insults (in the English speaking
world): "Oh Lord Mark," (mild) versus "Markus, you pompous ass,"
(nasty).  Remember insults, curses, formality and such don't
translate well interculturally.

> I'm still missing any arguments on your side

Perhaps you're following the argument in the "wrong" group (not that
comp.lang.functional is necessarily the wrong place for the discussion,
it'd certainly be better than cluttering up comp.lang.lisp from my
perspective, but it's not where a lot of the posting happened), and/or
are missing historical context from other threads.

Don't mistake lack of serious response to Jon this time around
as lack of any responses to Jon over the years- it just wears thin after
a while. Given certain peculiarities of human perception, Jon's
persistent postings in various fora could be considered rather more
harmful and nasty than many people might realise:
http://www.spring.org.uk/2007/07/loudest-voice-majority-opinion.php








0
Reply david.golden (499) 7/25/2007 7:34:31 PM

Markus E Leypold <development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de> writes:

> Actually I don't see: First I do not understand "Because it sells
> books" and second, should that really refer to the fact that Jon has
> written a book (and selling it for money), it still got me confused:
> 
>  1. Jon didn't hype his book in this thread.
>  
>  2. That someone is working in a given subject area X and actually is
>     making money from it -- is that disqualifying him from making
>     useful and true statements on usenet? As opposed to all the people
>     around with no history in area X and no success?
> 
> I'm puzzled.
> 
> Regards -- Markus

This Harrop creature is spamming comp.lang.lisp for a long time now.  IIRC
he even admitted that the main purpose of his posts was to make more sales
for his books.

Apparently, he is not behaving that bad in comp.lang.functional.  You can
call yourself lucky.

Yours, Nicolas
0
Reply lastname1 (71) 7/25/2007 8:40:36 PM

David Golden wrote:
>> That's exactly what I'm doing.
> 
> Well, that is silly.

The C++ and Qi type systems provide exactly the same capabilities. That is a
useful and objective classification.

Incidentally, this debate was covered in detail at the advent of ML 30 years
ago, long before Qi existed. ML chose a path. Haskell chose a similar path.
OCaml also. Qi chose to copy C++ instead.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/25/2007 10:01:38 PM

 >>>> Jon Harrop escreveu:
 >>>>> Pattern matching ... is the main reason why OCaml, SML,
 >>>>> Haskell and F# are all much more concise than Common Lisp.

 >>> Cesar Rabak wrote:
 >>>> I still find your comparison loaded: you rule out the use
 >>>> of libraries for pattern matching in Lisp. Why?

 >> Dan Bensen escreveu:
 >>> Because it sells books.

Markus E Leypold wrote:
 > Actually I don't see:
 >  1. Jon didn't hype his book in this thread.

First of all, Marcus, Jon's signature does advertise his book, so
he has directly advertised his book in this thread simply by posting
to it.  As for "hyping", it's not necessary to promote the book
directly.  It may be enough to draw programmers toward OCaml by making
comparisons that are unfairly biased against Lisp, which Jon has been
doing repeatedly.

 >  2. That someone is working in a given subject area X and actually is
 >     making money from it -- is that disqualifying him from making
 >     useful and true statements on usenet?

Markus, do you consider it "true and useful" to say that pattern-
matching libraries are "Greenspunning"?  Do you think ML languages
are "much more concise" than Lisp?  I don't think those statements
are either true or useful.  I don't think libraries and simple macros
are Greenspunning, and I don't think the ML family is "much" more
concise than Lisp when you take macros into account.

-- 
Dan
www.prairienet.org/~dsb/
0
Reply randomgeek (299) 7/26/2007 12:00:16 AM

Some entity, AKA Markus E Leypold <development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de>,
wrote this mindboggling stuff:
(selectively-snipped-or-not-p)

>  2. That someone is working in a given subject area X and actually is
>     making money from it -- is that disqualifying him from making
>     useful and true statements on usenet? As opposed to all the people
>     around with no history in area X and no success?
> 
> I'm puzzled.

Don't be,

It is rather simple, if you want to build a house there are is a long
list of 'environmental contraints' to it'sconstruction, like geology,
climate, availability and cost of materials, ease of maintenance and
change, to name just a few.
A good designed house can have a timberframe or reinforced concrete as the
base structure, both give an livingspave when finished, or any other
basic-structure for that matter.   
But if someone sells rebar, he will loath a timberframe as a
wood salesman wil pity any concrete setup.
Of course there are some drawbacks as to ease of change, which, with both,
can be a horror or a blessing, it just depends how often you want to go
through that ordeal.   

Cor

-- 
	 (defvar MyComputer '((OS . "GNU/Emacs") (IPL . "GNU/Linux"))) 
The biggest problem LISP has, is that it does not appeal to dumb people
    If all fails to satisfy you read the HyperSpec or info woman 
			 mailpolicy @ http://www.clsnet.nl/mail.php
0
Reply cor (124) 7/26/2007 12:20:39 AM

Jonnie Boy wrote:
> The C++ and Qi type systems provide exactly the same capabilities.
> That is a useful and objective classification. 

About as useful as more usual arguments from programming language turing 
completeness at run-time rather than some aspect
(type/template/macro/whatever) of a compile-time.  Yes, it
distinguishes Qi from ML.  No, it doesn't say much about which of Qi or
C++ is nicer.  Run-time turing-completeness doesn't say much about
whether Ruby or Intercal is nicer.

> Incidentally, this debate was covered in detail at the advent of ML 30
> years ago, long before Qi existed. 

That just serves to highlight that your retreading and retreading of the
same old debates ad nauseum in a multitude of fora is a quite
deliberate decision on your part, presumably in order to spam (Nor is
ocaml some great answer to all debate, it's just a particular set of
tradeoffs aligned with some people's preferences)

> Qi chose to copy C++ instead 

Much like Python "chose to copy" fortran's turing completeness at run
time when it could have just copied regexes?  Given the goals and
nongoals of Qi your comment is a tad vacuous at best.

What little point you are presumably dragging out making, in order to
turn one spam opportunity into many, and it's one that's already been
made quite a lot, including extremely recently - that one might opt for
a more limiting type system to ensure some desired static decidability
property - should have been taken to be understood and covered by the
just-supplied link to Mark Tarver's
http://www.lambdassociates.org/studies/study03.htm 

Yes, I promise to really killfile Harrop now and stop helping him spam:
http://groups.google.com/group/comp.lang.lisp/msg/7f66e71bdbcf0ffc



0
Reply david.golden (499) 7/26/2007 4:54:01 AM

Dan Bensen wrote:
> First of all, Marcus, Jon's signature does advertise his book, so
> he has directly advertised his book in this thread simply by posting
> to it.  As for "hyping", it's not necessary to promote the book
> directly.  It may be enough to draw programmers toward OCaml by making
> comparisons that are unfairly biased against Lisp, which Jon has been
> doing repeatedly.

Are you saying that Mark is conspiring to produce benchmarks that show Lisp
in a bad light?

> Markus, do you consider it "true and useful" to say that pattern-
> matching libraries are "Greenspunning"?  Do you think ML languages
> are "much more concise" than Lisp?  I don't think those statements
> are either true or useful.  I don't think libraries and simple macros
> are Greenspunning, and I don't think the ML family is "much" more
> concise than Lisp when you take macros into account.

Even though both languages have macros?

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/26/2007 7:35:22 AM

Jon Harrop wrote:

> I lurk on the Haskell Cafe mailing list and eager evaluation is often the
> solution to reliability or performance problems: laziness is unpredictable.

Do you have an example?

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/26/2007 7:59:44 AM

> > >>> Humm... I still find your comparison loaded: you rule out the use
> > >>> of libraries for pattern matching in Lisp. Why?
> > >> Because it sells books.
> > >>
> > > I see. . .

> > Actually I don't see: First I do not understand "Because it sells
> > books" and second, should that really refer to the fact that Jon has
> > written a book (and selling it for money), it still got me confused:

> >  2. That someone is working in a given subject area X and actually is
> >     making money from it -- is that disqualifying him from making
> >     useful and true statements on usenet? As opposed to all the people
> >     around with no history in area X and no success?
> > 
> > I'm puzzled.
>
> Don't be,
>
> It is rather simple, if you want to build a house there are is a long
> list of 'environmental contraints' to it'sconstruction, like geology,
> climate, availability and cost of materials, ease of maintenance and
> change, to name just a few.
> A good designed house can have a timberframe or reinforced concrete as the
> base structure, both give an livingspave when finished, or any other
> basic-structure for that matter.   
> But if someone sells rebar, he will loath a timberframe as a
> wood salesman wil pity any concrete setup.
> Of course there are some drawbacks as to ease of change, which, with both,
> can be a horror or a blessing, it just depends how often you want to go
> through that ordeal.   

Ah, I see. There is no need to actually give arguments against Jon's
position: It's automatically discredited by the fact that he makes a
living from his know-how which also implies that he MUST be
wrong. Absolutely.

We should probably handle our relationship to medical doctors the same
way: Not believing their diagnosis since they are -- GASP -- earning
money from their practice.

Or just wait -- now I see, it's all because Jon has no timber
reinforced concrete in his base structure libraries and is trying to
push a rebar book. It's all about architecture. Now there!

Well, well.

Regards -- Markus


0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/26/2007 9:11:30 AM

Frank Buss wrote:
> Jon Harrop wrote:
>> I lurk on the Haskell Cafe mailing list and eager evaluation is often the
>> solution to reliability or performance problems: laziness is
>> unpredictable.
> 
> Do you have an example?

Sure:

"Need for speed: the Burrows-Wheeler Transform" -
Andrew Coppin wrote a beautiful implementation of the Burrows-Wheeler
compression algorithm in Haskell. Using it to transform 4kB of data
required 60Mb of memory and scaled uncontrollably. After a month of
optimizing by experts, it remains orders of magnitude slower than
production implementations.

"Haskell version of ray tracer code is much slower than the original ML" -
Philip Armstrong had a go at translating my ray tracer into Haskell. The
first version is many times slower. After a week of intensive optimization
by several experts, it avoids laziness (acting as a poor ML) and remains
50% slower.

I have been evaluating Haskell for two months now, with a view to writing
a "Haskell for Scientists".

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/26/2007 9:19:35 AM

> Markus E Leypold wrote:
>
>>> http://xkcd.com/291/
>> 
>> And that tells us what, "Golden Boy Davy"? 
>
> That was directed more at *your* ridiculous levels of outrage at minor

Well. Probably you don't understand xkcd at all. That would explain
ist. (Just think: What is the message of this comic, actually? :-).

> childishness (at least interpreting your reaction naively, I could be
> more charitable and assume Germans find name diminution and/or
> childishness in general peculiarly offensive compared to English or
> Irish people. Neoteny being a defining characteristic of our species,

Ah, so calling JH "Jonnie boy" was a term of endearment, or what?
Believe me: I understand English much better than I write it, so don't
bullshit me.

> I'd recommend not being so down on childishness). 

Yes, I admit: Your behaviour is giving childishness a bad name. It's
the behaviour of a stupid and aggressive child.

> I'd expect Jon to be roughly as insulted by Jonnie Boy as I would be by
> Golden Boy. That is to say, very, very mildly. If anything, such

Oh yes. Fine. If you're not insulted, then it's OK. Regarding your
"answers" to JH it's the overall pattern:

  - no arguments
  - "mild" insults
  - F'up to alt.killfile
  - multiple followups to Jon's posts in that style 

> devices are usually used to soften insults (in the English speaking
> world): "Oh Lord Mark," (mild) versus "Markus, you pompous ass,"
> (nasty).  Remember insults, curses, formality and such don't
> translate well interculturally.

Oh yes. Because UK/GB is "another culture". Don't be ridiculous. The
differences are only slight.

>> I'm still missing any arguments on your side
>
> Perhaps you're following the argument in the "wrong" group (not that
> comp.lang.functional is necessarily the wrong place for the discussion,

I left the followups intact -- with the exception of those set to
alt.killfile. I suggest you answer where you post (that is in c.l.f)
or stop posting to c.l.f.

> it'd certainly be better than cluttering up comp.lang.lisp from my
> perspective, but it's not where a lot of the posting happened), and/or
> are missing historical context from other threads.

No. I'm not doing a usenet search do vindicate you. Your footprint in
c.l.f is what counts since I'm reading you at c.l.f and that was, I
repeat: Childish and without any arguments to be take seriously.

> Don't mistake lack of serious response to Jon this time around
> as lack of any responses to Jon over the years- it just wears thin after
> a while.

Yes, yes, yes: We know you don't like Jon. I don't care. Giving what I
have seen in the ant-Jon-threads at c.l.f that only reflects badly on
the c.l.l crowd: (As I think Jo Durchholz alread said:) I've
experienced Jon a rather persistent disputant with well defined
positions and opinions, never though as spammer or troll and never
totally unfair, though pushing his points rather aggressivly. I seldom
saw Jon holding a grudge against anybody (even people that more or
less would have insulted me), an attitude that strikes me as rather
professional. Jon also follows up his arguments and provides either
references to literature (off- and online) or sample code to at least
make his points plausible.

Indeed it strikes me that usenet would be a better (if perhaps more
exhausting) place if there were more people like Jon.

And to top that: Jon is a rather visible and committed participant in
usenet and various mailinglist discussion. I think he's entitled to
mention his book now and then. Even if it costs money.

(And no: I don't always like Jon's positions nor his way to argue.)

> Given certain peculiarities of human perception, Jon's
> persistent postings in various fora could be considered rather more
> harmful and nasty than many people might realise:
> http://www.spring.org.uk/2007/07/loudest-voice-majority-opinion.php

Certainly. Jon as a danger for public opinion. Pull the other one (got
bells on it).

Regards -- Markus


0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/26/2007 9:33:09 AM


BTW: You're F'upping to alt.killfile again. It's this kind of one-way
communication that in my eyes defines a spammer.

>
>> Incidentally, this debate was covered in detail at the advent of ML 30
>> years ago, long before Qi existed. 
>
> That just serves to highlight that your retreading and retreading of the
> same old debates ad nauseum in a multitude of fora is a quite
> deliberate decision on your part, presumably in order to spam (Nor is
> ocaml some great answer to all debate, it's just a particular set of
> tradeoffs aligned with some people's preferences)

Bah - nonsense. It serves to show that Jon has done his research
whereas other people haven't so insist on leading the same discussions
again and again (those who don't know their history are damned to
repeat it).

Regards -- Markus

0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/26/2007 9:37:12 AM

Jon Harrop wrote:

> "Need for speed: the Burrows-Wheeler Transform" -
> Andrew Coppin wrote a beautiful implementation of the Burrows-Wheeler
> compression algorithm in Haskell. Using it to transform 4kB of data
> required 60Mb of memory and scaled uncontrollably. After a month of
> optimizing by experts, it remains orders of magnitude slower than
> production implementations.

Looks like you mean this article:

http://www.mail-archive.com/haskell-cafe@haskell.org/msg25609.html

I can't see that the first version needed a month of optimizing and looks
like a prove for the opposite. Quoting from the posting:

"Woah... What the hell? I just switched to Data.ByteString.Lazy and WHAM!
Vast speed increases..."

I'm not a Haskell expert, but "Data.ByteString.Lazy" sounds very much like
lazy evaluation. And this last version in the first posting was already
faster by a factor of 4 than the C++ version, but it uses more memory.

> "Haskell version of ray tracer code is much slower than the original ML" -
> Philip Armstrong had a go at translating my ray tracer into Haskell. The
> first version is many times slower. After a week of intensive optimization
> by several experts, it avoids laziness (acting as a poor ML) and remains
> 50% slower.

Looks like you mean this article:

http://groups.google.com/group/fa.haskell/browse_thread/thread/797b6ff42a1171d2

I can't see "a week of intensive optimization", at least not for the lazy
part, which was suggested at the same day the first posting was made. The
benchmark was posted one day after the first posting, which says 38.2
seconds for the Haskell version and 23.8 seconds for the OCaml version.

But in general you may be right for this example that lazy evaluation was
slower than strict evaluation, I didn't studied the source code and run
benchmarks on both versions.

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/26/2007 10:08:02 AM

On Jul 24, 12:03 pm, Markus E Leypold
<development-2006-8ecbb5cc8aREMOVET...@ANDTHATm-e-leypold.de> wrote:
> > Dan Bensen escreveu:
> >> Cesar Rabak wrote:
> >>> Jon Harrop escreveu:
> >>>> Pattern matching is the single biggest advantage and is the main
> >>>> reason why OCaml, SML, Haskell and F# are all much more concise
> >>>> than Common Lisp.
> >>> Humm... I still find your comparison loaded: you rule out the use
> >>> of libraries for pattern matching in Lisp. Why?
> >> Because it sells books.
>
> > I see. . .
>
> Actually I don't see: First I do not understand "Because it sells
> books" and second, should that really refer to the fact that Jon has
> written a book (and selling it for money), it still got me confused:
>
>  1. Jon didn't hype his book in this thread.
Yes  he do. He even counts clicks coming from usenet :
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet

If you can't recognize spammer who doesn't even try to conceal himself
than ...I'm out of word.

>
>  2. That someone is working in a given subject area X and actually is
>     making money from it -- is that disqualifying him from making
>     useful and true statements on usenet?

It's disqualifying him from making unbiased statements.  How about
asking Oracle salesperson about strengths & weaknesses of various
DBMSs , "Postgre  don't make me lough ...MYSQL it's doesn't even
support ..., SQL Server runs only on ... DB2 it's too ..."

> As opposed to all the people
>    around with no history in area X and no success?

That's already insulting.





0
Reply slobodan.blazeski (1459) 7/26/2007 1:47:42 PM

On Jul 25, 6:28 pm, Tamas Papp <tkp...@gmail.com> wrote:
> Slobodan Blazeski <slobodan.blaze...@gmail.com> writes:
> > On Jul 24, 10:47 pm, Tamas Papp <tkp...@gmail.com> wrote:
> >> Joachim Durchholz <j...@durchholz.org> writes:
> >> > Nonsense. Stick with a few hard-and-fast rules, and you can get rid of
> >> > most parentheses.
>
> >> I wish that a blessed month could go by without somebody proposing
> >> this.
>
> >> Tamas
>
> > That's a definitely bad, as it would mean there's nobody who's
> > starting to learn  lisp. Some of them will whine and leave, the rest
> > will stay.
>
> I don't think that people who seriously want to learn Lisp go through
> the whine-about-parenthesis stage.  Anyone with at least a nontrivial
> interest in Lisp will read the first few chapters of a Lisp book, and
> by that time, they will see the light.
>
> My impression is that people who whine about parens have heard about
> how good Lisp is, didn't get it and started to complain about
> something trivial, or have been forced to learn some very basic Lisp
> in a bad college course and resent that.

I disliked lisp syntax , too many parens, at first. And what will be
this group without me and especially without my spelling errors?
>
> > Why do you prefer lisp over Ocaml/F# ?
>
> Fortunately, my acquaintance with Ocaml/F# is cursory, I have looked
> at Ocaml once and decided that it is not for me.  I tried Haskell last
> summer, but for the stuff I am doing (numerical analysis) lazy
> evaluation is not practical.  Lisp was almost perfect from the first
> moment, even before I learned about macros.
>
> > I would rather been called a savage than a spammer.
>
> ?

Google for savegs of cll or savages or lisp and you'll find a lot of
*nice discussions*. It reminds me of trolls non-stop posting that
FreeBSD is duying in the forums that most of the search hits for
FreeBSD leaded to those troll remarks. My favourite part is:

90% of Lispers give the other 10% a bad name, but generalizing in this
case
is like racism.
http://mail.python.org/pipermail/python-list/2003-October/230910.html

As per spammer word, lately every mention of OCaml / F# makes me feel
spammed . I wonder why?


"We have to improve our image in the internet community."
"Lets do a mass unsolicited email campaign to tell everyone how nice
we are."
<later> "You have the look of a man who was just put in charge of
implementing his own sarcastic suggestion."
        - The Pointy Haired Boss, Dilbert & Dogbert

0
Reply slobodan.blazeski (1459) 7/26/2007 1:56:39 PM

Jon Harrop <jon@ffconsultancy.com> wrote:
> I lurk on the Haskell Cafe mailing list

Hmm.  Most people's definition of "lurk" doesn't include posting. :)

> and eager evaluation is often the
> solution to reliability or performance problems: laziness is unpredictable.

True: eager evaluation is often the solution to performance problems.  
Equally true: lazy evaluation is often the solution to performance 
problems.  It would be nice if one or the other were always the right 
answer, but alas, that's not the case.

Interestingly, one thing that IS true is that eager-evaluation pure 
functional programs are actually asymptotically worse than alternatives 
for some problems.  That's part of why they don't exist.  Some languages 
(e.g., Haskell) choose to offer lazy evaluation to recover that lost 
performance.  Others (e.g., ML, Lisp) choose to offer impure language 
features to recover that lost performance.

-- 
Chris Smith
0
Reply cdsmith (3171) 7/26/2007 2:11:46 PM

> On Jul 24, 12:03 pm, Markus E Leypold
> <development-2006-8ecbb5cc8aREMOVET...@ANDTHATm-e-leypold.de> wrote:
>> > Dan Bensen escreveu:
>> >> Cesar Rabak wrote:
>> >>> Jon Harrop escreveu:
>> >>>> Pattern matching is the single biggest advantage and is the main
>> >>>> reason why OCaml, SML, Haskell and F# are all much more concise
>> >>>> than Common Lisp.
>> >>> Humm... I still find your comparison loaded: you rule out the use
>> >>> of libraries for pattern matching in Lisp. Why?
>> >> Because it sells books.
>>
>> > I see. . .
>>
>> Actually I don't see: First I do not understand "Because it sells
>> books" and second, should that really refer to the fact that Jon has
>> written a book (and selling it for money), it still got me confused:
>>
>>  1. Jon didn't hype his book in this thread.
> Yes  he do. He even counts clicks coming from usenet :
> http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet

God, no. He's even counting clicks! How depraved!

> If you can't recognize spammer who doesn't even try to conceal himself
> than ...I'm out of word.

I'm certain you can go and ask his provider to suspend his
access. Providers don't like spammers, I hear.

>>  2. That someone is working in a given subject area X and actually is
>>     making money from it -- is that disqualifying him from making
>>     useful and true statements on usenet?
>
> It's disqualifying him from making unbiased statements.  How about
> asking Oracle salesperson about strengths & weaknesses of various
> DBMSs , "Postgre  don't make me lough ...MYSQL it's doesn't even
> support ..., SQL Server runs only on ... DB2 it's too ..."

I absolutely concur that I don't need and don't want to take a sales
persons statements just on authority alone. But ...

 - JH sells a book and consulting services, not OCaml. He works with
   OCaml, he doesn't make OCaml. Should we now ostracize anybody who
   touts his (or her) tools? Like Linus Torvalds: He's working with
   Linux, he's even proved (with Linux) that he can program, now he
   even profits from that: Don't believe a single statement of what he
   says!? Linux is vaporware!

 - Having a stake in something doesn't prevent one from making true
   statements in that area. Statements don't become automatically
   untrue (this assumption is indeed one of the well know logical
   fallacies). Nobody expects that you take them by authority. You can
   disprove them or demand proof. But logically you can't disqualify
   them on the basis that the speaker might profit if/when they are
   true.

 - I understand that I'm expected to distrust everything Jon said,
   because he has written and is selling a book on OCaml. On the other
   side I'm expected to accept protestations from c.l.l about Lisp and
   what can be done with Lisp without further proof (i.e. a running
   program) even if a number of people there (like, e.g. Rainer
   Joswig) have undoubtly a professional reputation in that area?
   Isn't your logic somewhat flawed.

>> As opposed to all the people
>>    around with no history in area X and no success?
>
> That's already insulting.

How so? Do you seriously propose that everyone posting in c.l.l and
c.l.f has a proven track record in functional programming, is
qualified to make a comparison of functional languages and should
therefore be taken on authority? If so, why doesn't it apply to Jon
Harrop (who is posting on c.l.l ...)? If not, why is it insulting to
presume that not everyone posting in c.l.[fl], especially in this
thread here, has the qualification?

You mystify me.

Regards -- Markus
0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/26/2007 2:31:17 PM

Dan,

>  >>>> Jon Harrop escreveu:
>  >>>>> Pattern matching ... is the main reason why OCaml, SML,
>  >>>>> Haskell and F# are all much more concise than Common Lisp.
>
>  >>> Cesar Rabak wrote:
>  >>>> I still find your comparison loaded: you rule out the use
>  >>>> of libraries for pattern matching in Lisp. Why?
>
>  >> Dan Bensen escreveu:
>  >>> Because it sells books.
>
> Markus E Leypold wrote:
>  > Actually I don't see:
>  >  1. Jon didn't hype his book in this thread.
>
> First of all, Marcus, Jon's signature does advertise his book, so
> he has directly advertised his book in this thread simply by posting
> to it. 

Oh I see. How bad. If you follow my mail domain, you'll also find a
business web site (now somewhat out dated). Does that make me a
spammer too? And do you click on every link in signatures? I really
don't see how the word "hype" would apply to posting a link in a
signature. And what about www.prairienet.org/~dsb/? What about people
having their their company name in the sig?

> As for "hyping", it's not necessary to promote the book
> directly.  It may be enough to draw programmers toward OCaml by making
> comparisons that are unfairly biased against Lisp, which Jon has been
> doing repeatedly.

And pulling them to himself just by alienating them to Lisp. Don't be
ridiculous. Jon is not the only OCaml developer around.

>  >  2. That someone is working in a given subject area X and actually is
>  >     making money from it -- is that disqualifying him from making
>  >     useful and true statements on usenet?
>
> Markus, do you consider it "true and useful" to say that pattern-
> matching libraries are "Greenspunning"?  Do you think ML languages

Dan, actually I considered that as something that happens when the
discussion has alread detoriated enough - which certainly wasn't Jon's
doing alone. My dictionary doesn't contain the word "greenspunning" as
a verb, but I assume that Jon referred to "Greenspun's Tenth Rule"
which is, given the context, ironic, but, I think expresses very well,
why Jon distains pattern matching libraries in Lisp and thinks that
pattern matching belongs into the core language. So indeed the hint
'Greenspun' does communicate the argument very concisly.

> are "much more concise" than Lisp?  

Unfortunately I'm programming in ML languages rather than Lisp,
preferrably in OCaml. So ... -- I'm certainly biased. Regarding
pattern matching -- Yes, I think ML (and Haskell pattern matching is
more concise than anything of that kind I have seen in Lisp so far,
and certainly more than nesting of conditional statements. In ML it
also ties in rather nicely with the type system: In many cases the
compiler will warn you about forgotten cases -- something I imagine
the Lisp systems must have difficulties with owing to the dynamic type
system.

> I don't think those statements are either true or useful.

> I don't think libraries and simple macros are Greenspunning, and I

I wonder what you think "greenspunning" actually is?

> don't think the ML family is "much" more concise than Lisp when you
> take macros into account.

You believe that. Other people believe differently. How can you reach
agreement? Certainly not by ad hominem attacks and attacking straw men
(what, at the end of the day, the argument "he sells book" actually
is. And if I consider further, trying to contradict my lack of
understanding of this argument by constructing a case against JH by
some other route ("Greenspunning", "It's wrong than ML is more
concise") is also a strawman, because it makes the "he sells books"
argument not any more valid, not one iota).

Regards -- Markus

(Who think's that some of the participants in this slug fest should
better their logic by reading e.g. here:
http://www.nizkor.org/features/fallacies)




0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/26/2007 3:04:15 PM


> Markus E Leypold <development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de> writes:
>
>> Actually I don't see: First I do not understand "Because it sells
>> books" and second, should that really refer to the fact that Jon has
>> written a book (and selling it for money), it still got me confused:
>> 
>>  1. Jon didn't hype his book in this thread.
>>  
>>  2. That someone is working in a given subject area X and actually is
>>     making money from it -- is that disqualifying him from making
>>     useful and true statements on usenet? As opposed to all the people
>>     around with no history in area X and no success?
>> 
>> I'm puzzled.
>> 
>> Regards -- Markus
>
> This Harrop creature is spamming comp.lang.lisp for a long time now.  IIRC
> he even admitted that the main purpose of his posts was to make more sales
> for his books.

That doesn't refute (2). And as far as "spamming" goes: I have
observed in this thread that some people have a curious definition of
spamming. Can't follow you there either.

>
> Apparently, he is not behaving that bad in comp.lang.functional.  You can

And that despite Rainer's attempt to carry the fight over to c.l.f ...

> call yourself lucky.

Or is that an indicator that there you need always 2 to get into a
fight? That the c.l.l crowd is not so blameless either? 

Regards -- Markus




0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/26/2007 3:33:02 PM

Pascal Costanza wrote:
> Jon Harrop wrote:
>> Pascal Costanza wrote:
>>> No, exceptions can be implemented in a Common Lisp without exceptions
>>> already built in. For example, see
>>> http://www.nhplace.com/kent/CL/Revision-18.lisp
>>
>> Turing argument.
> 
> Quoted out of context.

Jon, I didn't get the intent of your post the first time around, and I 
apologize for my knee-jerk reaction.

Here is a more precise answer: For a good exception handling system, you 
don't need full continuations. One-shot escaping continuations + 
unwind-protect / try-finally / dynamic-wind, or the like, are 
sufficient, and core Common Lisp has both. You don't need to implement 
an interpreter for a different language that has continuations for 
implementing exception handling in core Common Lisp, and this is what 
the implementation behind the link above shows. So this has nothing to 
do with Turing equivalence - we have a true embedding of exception 
handling here.

So how are the benchmarks for my last version of the minim interpreter 
coming along?


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/26/2007 4:12:20 PM

Frank Buss wrote:
> "Woah... What the hell? I just switched to Data.ByteString.Lazy and WHAM!
> Vast speed increases..."

That is a Haskell vs Haskell comparison and says nothing in comparison with
other languages.

> I'm not a Haskell expert, but "Data.ByteString.Lazy" sounds very much like
> lazy evaluation. And this last version in the first posting was already
> faster by a factor of 4 than the C++ version, but it uses more memory.

As you might imagine, that is comparing Haskell with some pretty awful C++
code!

If you compare with good C++, you get a very different result as Stefan
O'Rear noted in that very same thread:

"Mr. C++ apparently isn't a very good C++ programmer, since his best
effort absolutely *pales* in comparison to Julian Seward's BWT: ... This C++
is 200 times faster."

http://www.mail-archive.com/haskell-cafe%40haskell.org/msg25645.html

> I can't see "a week of intensive optimization", at least not for the lazy
> part, which was suggested at the same day the first posting was made.

Philip Armstrong's first post with an already-optimized ray tracer was 21st
June:

  http://www.mail-archive.com/haskell-cafe%40haskell.org/msg25457.html

Spencer Janssen's major optimization was 25th June. Final version is dated
5th July:

  http://www.kantaka.co.uk/darcs/ray/

> The 
> benchmark was posted one day after the first posting, which says 38.2
> seconds for the Haskell version and 23.8 seconds for the OCaml version.
> 
> But in general you may be right for this example that lazy evaluation was
> slower than strict evaluation, I didn't studied the source code and run
> benchmarks on both versions.

You can convert from eager back to lazy easily in Haskell: just remove
the !s.

On my 2.2Ghz Athlon 64 dual core x64 Debian I get running times:

Lazy Haskell:   41.5s  75LOC  GHC 6.6.1
Eager Haskell:  18.7s  75LOC  GHC 6.6.1
OCaml:           7.2s  56LOC  OCaml 3.10.0

So idiomatic Haskell is ~6x slower than idiomatic OCaml on my machine.

Compile times:

GHC:   2.776s
OCaml: 0.375s

That was comparing the OCaml:

  http://www.ffconsultancy.com/languages/ray_tracer/comparison.html

to the Haskell (with and without the !s) by Philip Armstrong, Bulat
Ziganshin, Mark T.B. Carroll, Simon Marlow, Donald Bruce Stewart, Claus
Reinke and Spencer Janssen:

  http://www.kantaka.co.uk/darcs/ray/

I also found it interesting that this trivial benchmark showed up several
bugs in GHC.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/26/2007 4:28:39 PM

Pascal Costanza wrote:
>>> Turing argument.
>> 
>> Quoted out of context.
> 
> Jon, I didn't get the intent of your post the first time around, and I
> apologize for my knee-jerk reaction.

No worries.

> Here is a more precise answer: For a good exception handling system, you
> don't need full continuations. One-shot escaping continuations +
> unwind-protect / try-finally / dynamic-wind, or the like, are
> sufficient, and core Common Lisp has both. You don't need to implement
> an interpreter for a different language that has continuations for
> implementing exception handling in core Common Lisp, and this is what
> the implementation behind the link above shows. So this has nothing to
> do with Turing equivalence - we have a true embedding of exception
> handling here.

Yes. This wasn't as bad as the other thread but I think the whole thing is
spiralling into a simple Turing argument. There is no easy way to add
callcc to Lisp (or OCaml).

> So how are the benchmarks for my last version of the minim interpreter
> coming along?

Your compiler-in-Lisp was the fastest of all implementations that I
benchmarked. PILS and Qi are the slowest. However, there was a Minim->C
compiler written in Haskell that I've yet to test but that, of course, will
be almost unbeatable (and compile time for such a small target program will
be insignificant).

When I can find the time I'll write a Minim->C compiler in OCaml and a
staged Minim interpreter in MetaOCaml.

How's the lexer/parser in Lisp going? :-)

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/26/2007 4:35:39 PM

Jon Harrop wrote:
> When I can find the time I'll write a Minim->C compiler in OCaml and a
> staged Minim interpreter in MetaOCaml.

I'd be interested to see the code for the latter.

> How's the lexer/parser in Lisp going? :-)

Syntax is for sissies. ;)


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/26/2007 5:25:17 PM

Pascal Costanza <pc@p-cos.net> writes:

> Syntax is for sissies. ;)

But without syntax what would there be to do timings on?

Some languages just gotta make work for themselves so their practitioners
will have something to bill for in terms of implementation, timing, tuning,
training, debugging, interfacing, etc. ... it's a whole industry.
0
Reply pitman (1396) 7/26/2007 10:57:25 PM

Kent M Pitman wrote:
> Some languages just gotta make work for themselves so their practitioners
> will have something to bill for in terms of implementation, timing,
> tuning, training, debugging, interfacing, etc. ... it's a whole industry.

Indeed. Writing a Mathematica to C# compiler would pay the bills if nothing
else...

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/26/2007 11:14:14 PM

Joachim Durchholz schrieb:

> I'm well aware that macros are a different concept than functions.
> 
> But that's not what I'm talking about; all I want to say is that Lisp's 
> insistence on not having operator precedence comes at the price of 
> having to write lots of parentheses when entering code. And that these 
> parentheses, tiny as they are in isolation, take up a good deal of 
> screen space because there are so many of them.

That Lisp has all these parens has mainly two reasons.
First: they organize code itself in trees, making it trivially 
transformable.
Translation into a syntax tree is not important anymore, because code
already is one. Having so easy accessible macros comes from representing
code inside one of the most flexible datastructures.
But even if we ignore that there is another design descision:
having functions that can take any number of arguments.
To make that possible you need two tokens. The parens just look
better than most other stuff.

One might think: hey, why not making the first argument to a function
call always the number of arguments that will follow?
Then no parens are needed. Instead of (+ 1 2 3) we would say:
+ 3 1 2 3
But then the problem is that an argument can be a function call itself.
So we need another token for that which means: function application will
follow. Let's make it "�". So instead of (+ 1 (* 1 2) 3) we say:
+ 3 1 $ * 2 1 2 3
Again we have two tokens. The new argument and �, instead of ( and ).
And if you ask me: I know which I prefer.

With the descision of allowing functions that take any number of
arguments Lisp has the nice feature that packing data into a list before
making it an argument is done by the compiler.
(+ 1 2 3) instead of (+ (list 1 2 3))


> What, then, is a place?

Do you know C? Think about something that is on the left side of a "=".
Left hand value.
x[5] = 100;
Then x[5] is the place. A place is a syntactical construct that looks
like accessing a value. x[5] will in nearly all cases get replaced by
the compiler with its value. But on the left side of a  =  it behaves
different. If x[5] == 17 then
x[5] = 100;
does not mean
17 = 100;


> Code transformation is done by the compiler in Haskell.
> Abstraction (i.e. new languages) is daily staple in Haskell. Sure, 
> Haskell embedded languages cannot do fancy syntax, but if you're fine 
> with frugal syntax, you define your embedded language simply as a set of 
> HOFs to use.

You can do the same in Lisp by making things lazy. In Lisp it would be
uglier than in Haskell because you would explicitily say
(delay (+ 1 2 3)) and (force xyz).
And yes, I think with lazy evaluation Haskell comes much closer to what
macros can do in a usable way than most other languages.


 > All without macros...

Lisp could also do it. But it does not have to rely on lazyness.
In Lisp you get very nice syntactical abstractions.
All without lazyness...



Andr�
-- 
0
Reply address.good.until.2007.dec.26 (60) 7/26/2007 11:49:20 PM

Andr� Thieme wrote:
> Translation into a syntax tree is not important anymore, because code
> already is one.

Assuming, of course, that you never want to communicate with the outside
world, where everyone has ditched s-exprs in favour of a plethora of
domain-specific syntaxes: C, C++, Java, C#, regexps, dna, protein, html,
xml, svg, sql.

In practice, s-exprs are so rare outside Lisp/Scheme that a "syntax is not
important anymore" attitude gets you nowhere.

> Lisp could also do it.

Turing argument.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/26/2007 11:57:32 PM

Andr� Thieme  <address.good.until.2007.dec.26@justmail.de> writes:
>That Lisp has all these parens has mainly two reasons.

  Historically, LISP started as a List-processing package 
  for FORTRAN. The parentheses were in there, because this
  was the list notation of that time.

  Then Steve Russel implemented EVAL - and the parentheses were
  in the language because EVAL was evaluating those List.

  So actually, the parentheses notation was there first, then
  followed the interpretation of its expressions as programs.

0
Reply ram (2828) 7/27/2007 12:05:12 AM

Jon Harrop schrieb:
> Andr� Thieme wrote:
>> Translation into a syntax tree is not important anymore, because code
>> already is one.
> 
> Assuming, of course, that you never want to communicate with the outside
> world, where everyone has ditched s-exprs in favour of a plethora of
> domain-specific syntaxes: C, C++, Java, C#, regexps, dna, protein, html,
> xml, svg, sql.

html is in nearly all cases like s-expressions plus noise and xml is
in all cases like s-expressions plus noise.
I don't know if there exist more lines of code in the languages C, C++,
Java and C# or more xml...


> In practice, s-exprs are so rare outside Lisp/Scheme that a "syntax is not
> important anymore" attitude gets you nowhere.

Although Java and C# are so called modern languages with lots of syntax
they are usually much more verbose than Lisp code.
Which Syntax is better for what case? As soon your language comes with
syntax someone else (the language designer) decided what the users have
to use. Every year a new language comes out and suggests to use a new
syntax. Each has its specific advantages. Lisp is the language that
initially comes without syntax. This puts you into the position to have
them all.


>> Lisp could also do it.
> 
> Turing argument.

You are not right this time. It is easy in Lisp.
Explicit laziness can be done in a few LOC. Look into PAIP.


Andr�
-- 
0
Reply address.good.until.2007.dec.26 (60) 7/27/2007 12:31:57 AM

[ comp.lang.lisp only.
  http://www.nhplace.com/kent/PFAQ/cross-posting.html ]

ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Andr� Thieme  <address.good.until.2007.dec.26@justmail.de> writes:
> >That Lisp has all these parens has mainly two reasons.
> 
>   Historically, LISP started as a List-processing package 
>   for FORTRAN. The parentheses were in there, because this
>   was the list notation of that time.
> 
>   Then Steve Russel implemented EVAL - and the parentheses were
>   in the language because EVAL was evaluating those List.
> 
>   So actually, the parentheses notation was there first, then
>   followed the interpretation of its expressions as programs.

MACLISP, up until the late 1970's, I think, allowed commas as
whitespace characters, allowing one to write (a,b,c) meaning (a b c).
It wasn't until backquote came along that we had to give up commas a
"superfluous", at least in the Maclisp family of languages.  I kicked
and screamed a bit about that, because I liked using commas as
whitespace.  But I don't think most people made much noise about
losing the commas.  [Though there was quite a competition for the
detailed syntax/semantics of the notation, since there were lots of
private variations.]
0
Reply pitman (1396) 7/27/2007 12:43:57 AM

Chris Smith <cdsmith@twu.net> writes:
>Interestingly, one thing that IS true is that eager-evaluation pure 
>functional programs are actually asymptotically worse than alternatives 

  Here is an article about a lazy Lisp, including an introduction
  to some related aspects of Lisp:

http://arxiv.org/abs/0707.3807

0
Reply ram (2828) 7/27/2007 12:58:21 AM

Markus E.L. wrote:
> You believe that. Other people believe differently. How can you reach
> agreement?

You can do objective and quantitative tests by writing equivalent programs
in different languages and measuring their verbosity, e.g. the ray tracer,
the symbolic simplifier, the Minim interpreter.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 1:37:00 AM

Some entity, AKA development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus E.L.),
wrote this mindboggling stuff:
(selectively-snipped-or-not-p)

> Or just wait -- now I see, it's all because Jon has no timber
> reinforced concrete in his base structure libraries and is trying to
> push a rebar book. It's all about architecture. Now there!
> 
> Well, well.

Of course not, it's about the paintjob ...
allmost nobody cares what hides behind that shiny layer.

Cor
-- 
	 (defvar MyComputer '((OS . "GNU/Emacs") (IPL . "GNU/Linux"))) 
The biggest problem LISP has, is that it does not appeal to dumb people
    If all fails to satisfy you read the HyperSpec or info woman 
			 mailpolicy @ http://www.clsnet.nl/mail.php
0
Reply cor (124) 7/27/2007 1:54:13 AM

> Bah - nonsense. It serves to show that Jon has done his research
> whereas other people haven't so insist on leading the same discussions
> again and again 

Other people insist on leading?  While he certainly prefers to chime in
to existing arguments, presumably because it initially looks a bit more
legitimate, if it's a slow day in the forum he's targetting and he
can't find a thread to try to latch on to (e.g. anything Mark Tarver
ever posts about Qi) or a newbie to "help" [1], he'll just try to
initiate, posting some rehashed flamebait or other (below are just
small examples, not at all exhaustive) to try to get things going:

http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/9f3219d715a24d01/
"Most people have managed to uninstall Lisp but many are still having
trouble unlearning it."

http://groups.google.com/group/comp.lang.java.programmer/msg/f1ccc1e85f109f68
"This seems to offer all of the benefits of the Java run-time from a
decent language."

> (those who don't know their history are damned to repeat it)

A salutary lesson for anyone who responds to Jon Harrop's persistent
trolling/spamming.

He may be on his best behaviour or on-topic in comp.lang.functional or
something, but elsewhere it's a quite different story. I'd assume many
subscribers to groups he's victimized in the past would consider your
defence of Harrop naive (and responding at all to Harrop quite annoying
troll-feeding on my and other's parts...).

[1] http://groups.google.com/group/comp.lang.lisp/msg/eee9ebe08d188455
"> There are several implementations or flavors of LISP.  Where do I
start? Which ones used the most?
[...]
You may wish to learn some of the modern, statically-typed Lisp variants
that have been developed over the past 30 years such as OCaml, Haskell
and F#. These are the flagship languages of the Lisp family.
"



0
Reply david.golden (499) 7/27/2007 3:23:33 AM

> I'm certain you can go and ask his provider to suspend his
> access. Providers don't like spammers, I hear.
> 

That's probably why he bothers to supply bodies in his posts, as
outlined by some helpful soul in
http://groups.google.com/group/comp.lang.lisp/msg/7f66e71bdbcf0ffc



0
Reply david.golden (499) 7/27/2007 3:24:09 AM

> Who think's that some of the participants in this slug fest should
> better their logic by reading e.g.

Here's one that's particularly relevant:
http://www.lambdassociates.org/fallacy.htm


0
Reply david.golden (499) 7/27/2007 4:39:07 AM

 > Regards -- Markus (Who think's that some of the participants in
 > this slug fest should better their logic by reading e.g. here:
 > http://www.nizkor.org/features/fallacies)

Markus, I've already KF'd you, because I find your posts misleading
and argumentative.  But since you went so far as to cite logical
fallacies, I'll describe the fallacies that you've been commiting.
Your main problem seems to be an inability to address comments
without distorting them, which is classic trolling behavior.

 >> Markus E Leypold wrote:
 >>  > Actually I don't see:
 >>  >  1. Jon didn't hype his book in this thread.
 >>
 >> First of all, Marcus, Jon's signature does advertise his book, so
 >> he has directly advertised his book in this thread simply by posting
 >> to it.

Markus E.L. wrote:
 > Oh I see. How bad.

Straw man.
http://www.nizkor.org/features/fallacies/straw-man.html

I never said advertising was bad.  I only suggested that your
statement was inaccurate, because Jon hypes OCaml and advertises
his book.

 >> As for "hyping", it's not necessary to promote the book directly.
 >> It may be enough to draw programmers toward OCaml by making
 >> comparisons that are unfairly biased against Lisp, which Jon
 >> has been doing repeatedly.

 > And pulling them to himself just by alienating them to Lisp.
 > Don't be ridiculous. Jon is not the only OCaml developer around.

Red herring.
http://www.nizkor.org/features/fallacies/red-herring.html

The question is not whether other OCaml developers post to the usenet,
but whether Jon has been trolling.  He has been the only developer
regularly making comparisons that are unfairly biased against Lisp.

 >> Markus, do you consider it "true and useful" to say that
 >> pattern-matching libraries are "Greenspunning"?

 > I think expresses very well, why Jon distains pattern matching
 > libraries in Lisp and thinks that pattern matching belongs into
 > the core language.  So indeed the hint 'Greenspun' does communicate
 > the argument very concisly.

Red herring.

The question is not whether the term expresses a sentiment, but
whether the sentiment is warranted.  I don't think a simple library
counts as "Greenspunning".

 >> Do you think ML languages are "much more concise" than Lisp?

 > Unfortunately I'm programming in ML languages rather than Lisp,
 > preferrably in OCaml. So ... -- I'm certainly biased. Regarding
 > pattern matching -- Yes, I think ML (and Haskell pattern matching is
 > more concise than anything of that kind I have seen in Lisp so far,
 > and certainly more than nesting of conditional statements.

Red herring.

We're not talking about the conciseness of pattern matching alone.
We're talking about the overall conciseness of each language,
based on pattern matching, macros, and all other features.

 >> I don't think libraries and simple macros are Greenspunning
 > I wonder what you think "greenspunning" actually is?

Regardless of its exact definition, it's a derogatory term that
suggests an inefficient, unmaintainable, unnecessary implementation
of features built into another language.  Macros make Lisp pattern-
matching libraries both efficient and maintainable, and ML's lack
of macros makes these libraries necessary if one wants both macros
and pattern matching.

 >> I don't think the ML family is "much" more concise than Lisp
 >> when you take macros into account.

 > You believe that. Other people believe differently. How can you reach
 > agreement? Certainly not by ad hominem attacks and attacking straw men
 > (what, at the end of the day, the argument "he sells book" actually
 > is.

Straw man.

No-one objects to selling books.  Only to trolling.

 > And if I consider further, trying to contradict my lack of
 > understanding of this argument

I don't contradict your lack of understanding at all, Markus.
I totally agree that you lack a basic understanding of Jon's
trolling and what other people have been saying to you.

 > by constructing a case against JH by some other route
 > ("Greenspunning", "It's wrong than ML is more concise")
 > is also a strawman, because it makes the "he sells books"
 > argument not any more valid, not one iota).

Obvious straw man, made even worse by appealing to the straw-man
fallacy yourself.  It's Jon who's making the Greenspunning arguments,
and no-one objects to selling books.  I think you're another troll.

-- 
Dan
www.prairienet.org/~dsb/
0
Reply randomgeek (299) 7/27/2007 5:11:28 AM

On 2007-07-26 10:31:17 -0400, 
development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus 
E.L.) said:

> You mystify me.

Let's put it simply:

1. A definition of spam is "communication that is irrelevant or 
inappropriate to a given forum, often advertising a commercial product 
or service."
2. From (1) we see that:

business signature + on topic for forum = legitimate post

business signature + off topic for forum = spam


3. Jon often posts to c.l.l *only*  (i.e., without also posting to c.l.f.)
4. Jon's often posts about ocaml to c.l.l *only*.
5. Posts about ocaml, though on topic in c.l.f., are certainly off 
topic in c.l.l.
6. Since Jon posts to an inappropriate forum (posts about ocaml to 
c.l.l) with a commercial signature (i.e., advertising commercial 
products and services) his posts about ocaml to c.l.l. are spam.

In summary:

If you post on topic to any forum with your business signature it is 
not spam because your post is *on topic for that forum*. If you post 
off topic to any forum with your business signature it is *spam*.

Since his posts to c.l.l are overwhelmingly off topic for his 
participation in that forum with his business signature is spam.

To conclude:

Jon should post to c.l.f. about ocaml but he doesn't - why? Because 
comparatively few people read or post to c.l.f. and Jon's aim is to 
reach as many potential customers has possible. So Jon spams the full 
house of c.l.l. instead of posting to the appropriate, but 
comparatively empty theater of c.l.f.




0
Reply Raffael 7/27/2007 5:15:48 AM

Markus E.L. wrote:

> Ah, so calling JH "Jonnie boy" was a term of endearment, or what?

If anything I was politely mocking his childish argumentation here and
elsewhere. e.g. his supplying of a substantially operationally
different ML line back when identifier length choices were being
pointed out as one reason the Qi code was presenting was relatively
inflated. 

Remember, the example as I gave it was to just to illustrate an effect
of identifier lengths on perceived code length, comparing long-looking
Qi and shorter Qi, not the effect of global implementation structural
choices or even directly comparing Qi and ocaml lines (Jon tried to do
that) rather than identifier length styles.

Are *you* going to assert the below Qi[1] and ocaml ML[1] are "the
same"? And then expect I dive into a childishly diversionary tarpit of
explaining all differences, allowing "you" (imagining you were Jon) to
divert and prolong argument?  Sure, Mark's Qi and Jon's ocaml programs
as a whole might both achieve running of "minim", but come on. And
consider Qi[2] (which is still not "the same" really, just hinting at
how someone might have written a more globally structurally Jon's-like
implementation in Qi). 

Qi[1]:
[[if X then A else B] | Ss] P E ->
        (if (pt X E) (rl [A | Ss] P E) (rl [B | Ss] P E))

ML[1]:

`If(p, f, g) -> s n (if t p then f else g)


Qi[2]:
n [if P F G] -> (s n (if (e P) F G))
 





0
Reply david.golden (499) 7/27/2007 6:06:01 AM

David Golden wrote:
 
> Qi[2]:
> n [if P F G] -> (s n (if (e P) F G))

s/n/N/g ... 







0
Reply david.golden (499) 7/27/2007 6:31:25 AM

In article <a73azbtc29.fsf@hod.lan.m-e-leypold.de>,
 development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus 
 E.L.) wrote:

> > Markus E Leypold <development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de> writes:
> >
> >> Actually I don't see: First I do not understand "Because it sells
> >> books" and second, should that really refer to the fact that Jon has
> >> written a book (and selling it for money), it still got me confused:
> >> 
> >>  1. Jon didn't hype his book in this thread.
> >>  
> >>  2. That someone is working in a given subject area X and actually is
> >>     making money from it -- is that disqualifying him from making
> >>     useful and true statements on usenet? As opposed to all the people
> >>     around with no history in area X and no success?
> >> 
> >> I'm puzzled.
> >> 
> >> Regards -- Markus
> >
> > This Harrop creature is spamming comp.lang.lisp for a long time now.  IIRC
> > he even admitted that the main purpose of his posts was to make more sales
> > for his books.
> 
> That doesn't refute (2). And as far as "spamming" goes: I have
> observed in this thread that some people have a curious definition of
> spamming. Can't follow you there either.
> 
> >
> > Apparently, he is not behaving that bad in comp.lang.functional.  You can
> 
> And that despite Rainer's attempt to carry the fight over to c.l.f ...

That's a lie, Markus. 

> 
> > call yourself lucky.
> 
> Or is that an indicator that there you need always 2 to get into a
> fight? That the c.l.l crowd is not so blameless either? 
> 
> Regards -- Markus

-- 
http://lispm.dyndns.org
0
Reply joswig8642 (2198) 7/27/2007 7:39:45 AM

development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus E.L.) writes:

> Dan,
> 
> >  >>>> Jon Harrop escreveu:
> >  >>>>> Pattern matching ... is the main reason why OCaml, SML,
> >  >>>>> Haskell and F# are all much more concise than Common Lisp.
> >
> >  >>> Cesar Rabak wrote:
> >  >>>> I still find your comparison loaded: you rule out the use
> >  >>>> of libraries for pattern matching in Lisp. Why?
> >
> >  >> Dan Bensen escreveu:
> >  >>> Because it sells books.
> >
> > Markus E Leypold wrote:
> >  > Actually I don't see:
> >  >  1. Jon didn't hype his book in this thread.
> >
> > First of all, Marcus, Jon's signature does advertise his book, so
> > he has directly advertised his book in this thread simply by posting
> > to it. 
> 
> Oh I see. How bad. If you follow my mail domain, you'll also find a
> business web site (now somewhat out dated). Does that make me a spammer
> too? And do you click on every link in signatures? I really don't see how
> the word "hype" would apply to posting a link in a signature. And what
> about www.prairienet.org/~dsb/? What about people having their their
> company name in the sig?

The sig is only a problem because of his other behaviour.  As I said
before, his posts probably fit better for comp.lang.functional.  On the
other hand, I am reading comp.lang.lisp (no followups set there, so I
probably won't read answers to this message).  Maybe you can understand
that I do not want to hear the continued promotion of OCaml and F# in a
lisp newsgroup.  (And, BTW, it is often a very brain-dead promotion,
because the guy deliberately refuses to understand other people arguments.)

Nicolas
0
Reply lastname1 (71) 7/27/2007 7:44:10 AM

development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus E.L.) writes:

> > Markus E Leypold <development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de> writes:
> >
> >> Actually I don't see: First I do not understand "Because it sells
> >> books" and second, should that really refer to the fact that Jon has
> >> written a book (and selling it for money), it still got me confused:
> >> 
> >>  1. Jon didn't hype his book in this thread.
> >>  
> >>  2. That someone is working in a given subject area X and actually is
> >>     making money from it -- is that disqualifying him from making
> >>     useful and true statements on usenet? As opposed to all the people
> >>     around with no history in area X and no success?
> >> 
> >> I'm puzzled.
> >> 
> >> Regards -- Markus
> >
> > This Harrop creature is spamming comp.lang.lisp for a long time now.  IIRC
> > he even admitted that the main purpose of his posts was to make more sales
> > for his books.
> 
> That doesn't refute (2). And as far as "spamming" goes: I have
> observed in this thread that some people have a curious definition of
> spamming. Can't follow you there either.

As I said elsewhere, the sig is no problem per se, but if it is contained
in hundreds of OCaml/F# promoting posts in a newsgroup where this stuff
does not belong, it is a clear sign for either trolling or spamming (choose
one of those).

> Or is that an indicator that there you need always 2 to get into a
> fight? That the c.l.l crowd is not so blameless either?

Believe what you want.  Do I really have to go through the last months of
comp.lang.lisp to prove my fact?  Maybe you can tell me why his profile

http://groups.google.de/groups/profile?enc_user=I_YUthUAAACWD_8VFKtRU42NeunWF-drfMq7BcOOnMpM9MYZ86CqoA&hl=en

is so bad and shows more posts in comp.lang.lisp than everywhere else...

Nicolas

0
Reply lastname1 (71) 7/27/2007 7:58:27 AM

Hi Marcus
I haven't heard that Linus Torvalds  came everyday to bother people in
newsgroups or forums specially dedicated to discuss Windows, FreeBSD &
Solaris and tells them how their OS sucks and they should switch to
Linux immediately. That's exactly what our resident spammer is doing
for a long, long time. Beside you are forgetting the economical
factor, spammer is here to sell his merchandise, he is at a his
working place right here to find every statements and read every study
that helps him achieve his goal, the other posters come only to read
something interesthing and answer with whatever free time they want to
spare. So spammer could spent days finding examples that makes his
views look better while the people who want to challenge his remarks
have only minutes.That makes his views biased, you can listen them and
you can try them but whatever you do keep in mind that his final goal
is to sell.

regards
Slobodan

0
Reply slobodan.blazeski (1459) 7/27/2007 8:26:22 AM

>> Here is a more precise answer: For a good exception handling system, you
>> don't need full continuations. One-shot escaping continuations +
>> unwind-protect / try-finally / dynamic-wind, or the like, are
>> sufficient, and core Common Lisp has both. You don't need to implement
>> an interpreter for a different language that has continuations for
>> implementing exception handling in core Common Lisp, and this is what
>> the implementation behind the link above shows. So this has nothing to
>> do with Turing equivalence - we have a true embedding of exception
>> handling here.
>
> Yes. This wasn't as bad as the other thread but I think the whole thing is
> spiralling into a simple Turing argument. There is no easy way to add
> callcc to Lisp (or OCaml).


Jon -- what do you mean by "not easy" here: Not easy in the current
implementations or is callc somehow in conflict with the language
structure itself? What I'm aiming at is the question wether a
different runtime (with a different stack implementation like most
scheme implementations I know of) would allow integrating callc to
OCaml and/or Lisp. On the other side, if that was not possible
(because callcc is somehow in conflict with the rest of the language
definition) that would mean that there would be no efficient or
straight forward compiler from Lisp and/or OCaml to Scheme, something
I always considered doable, though perhaps not desirable.  


Regards -- Markus
0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 8:58:32 AM

> Markus E.L. wrote:
>> You believe that. Other people believe differently. How can you reach
>> agreement?
>
> You can do objective and quantitative tests by writing equivalent programs
> in different languages and measuring their verbosity, e.g. the ray tracer,
> the symbolic simplifier, the Minim interpreter.

I think you got the message :-). I don't think those test provide
really hard irrefutable data, but at least some material for further
discussion and pondering. What I find so repugnant in many language
advocacy discussion how people already just know what is true and
right and so few ever are willing to go into formulating meaningful
questions and considering them in a more scientific spirit (meaning,
actually looking for answers instead of knowing them and trying to
convince the rest of the world. In my opinion that is what
distinguishes science from politics, not wether one got a research
grant or a PHD :-)).

Regards -- Markus





0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 9:05:08 AM


>> Who think's that some of the participants in this slug fest should
>> better their logic by reading e.g.
>
> Here's one that's particularly relevant:
> http://www.lambdassociates.org/fallacy.htm

To the discussion as a whole: yes. To the particular fallacy I've been critising: No.

Regards -- Markus
0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 9:07:30 AM

>>>>> "M.E.L." == Markus E L <development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de> writes:

  M.E.L.> In many cases the compiler will warn you about forgotten
  M.E.L.> cases -- something I imagine the Lisp systems must have
  M.E.L.> difficulties with owing to the dynamic type system.

In Erlang (which is dynamically typed), the compiler warns about
clauses that can never match, and a companion tool called Dialyzer
(part of Erlang/OTP) does dataflow analysis on programs, 
collecting type information, and warns about all sorts of things,
such as unreachable code, calling a function with incompatible types,
etc. Since the language is dynamic, even Dialyzer can't warn against
forgotten cases -- there is no template from which to judge that,
other than the derived signatures of the call sites. Thus, Dialyzer
can often tell whether a function is calling another using a type
that is not handled.

To illustrate with a simple (but fresh) example, the following
bug report came in a few days ago:

"Dialyzer issues a warning when matching the result of os:version:


   OSVersion = case os:version() of
      {Major, Minor, Release} ->
         lists:flatten(
            io_lib:format("~w.~w.~w",
                          [Major, Minor, Release]));
      VersionString ->
         VersionString
   end,


Dialyzer says on this code:
The variable VersionString can never match since previous
clauses completely covered the type 
{non_neg_integer(),non_neg_integer(),non_neg_integer()}


However, the documentation of os.erl says:
version() -> {Major, Minor, Release} | VersionString

Dialyzer or the documentation has it wrong."

Dialyzer is described e.g. in this document:
http://user.it.uu.se/~kostis/Papers/bugs05.pdf

A companion tool, TypEr is described here:
http://www.erlang.se/workshop/2005/TypEr_Erlang05.pdf

Clearly, one can perform quite advanced type analysis on 
dynamically typed languages.

BR,
Ulf W
-- 
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Team Leader, Software Characteristics
 / / /     Ericsson AB, IMS Gateways
0
Reply etxuwig (64) 7/27/2007 9:25:20 AM

On Jul 27, 7:11 am, Dan Bensen <randomg...@cyberspace.net> wrote:
>  > Regards -- Markus (Who think's that some of the participants in
>  > this slug fest should better their logic by reading e.g. here:
>  >http://www.nizkor.org/features/fallacies)
>
> Markus, I've already KF'd you, because I find your posts misleading
> and argumentative.  But since you went so far as to cite logical
> fallacies, I'll describe the fallacies that you've been commiting.
> Your main problem seems to be an inability to address comments
> without distorting them, which is classic trolling behavior.
>
>  >> Markus E Leypold wrote:
>  >>  > Actually I don't see:
>  >>  >  1. Jon didn't hype his book in this thread.
>  >>
>  >> First of all, Marcus, Jon's signature does advertise his book, so
>  >> he has directly advertised his book in this thread simply by posting
>  >> to it.
>
> Markus E.L. wrote:
>
>  > Oh I see. How bad.
>
> Straw man.http://www.nizkor.org/features/fallacies/straw-man.html
>
> I never said advertising was bad.  I only suggested that your
> statement was inaccurate, because Jon hypes OCaml and advertises
> his book.
>
>  >> As for "hyping", it's not necessary to promote the book directly.
>  >> It may be enough to draw programmers toward OCaml by making
>  >> comparisons that are unfairly biased against Lisp, which Jon
>  >> has been doing repeatedly.
>
>  > And pulling them to himself just by alienating them to Lisp.
>  > Don't be ridiculous. Jon is not the only OCaml developer around.
>
> Red herring.http://www.nizkor.org/features/fallacies/red-herring.html
>
> The question is not whether other OCaml developers post to the usenet,
> but whether Jon has been trolling.  He has been the only developer
> regularly making comparisons that are unfairly biased against Lisp.
>
>  >> Markus, do you consider it "true and useful" to say that
>  >> pattern-matching libraries are "Greenspunning"?
>
>  > I think expresses very well, why Jon distains pattern matching
>  > libraries in Lisp and thinks that pattern matching belongs into
>  > the core language.  So indeed the hint 'Greenspun' does communicate
>  > the argument very concisly.
>
> Red herring.
>
> The question is not whether the term expresses a sentiment, but
> whether the sentiment is warranted.  I don't think a simple library
> counts as "Greenspunning".
>
>  >> Do you think ML languages are "much more concise" than Lisp?
>
>  > Unfortunately I'm programming in ML languages rather than Lisp,
>  > preferrably in OCaml. So ... -- I'm certainly biased. Regarding
>  > pattern matching -- Yes, I think ML (and Haskell pattern matching is
>  > more concise than anything of that kind I have seen in Lisp so far,
>  > and certainly more than nesting of conditional statements.
>
> Red herring.
>
> We're not talking about the conciseness of pattern matching alone.
> We're talking about the overall conciseness of each language,
> based on pattern matching, macros, and all other features.
>
>  >> I don't think libraries and simple macros are Greenspunning
>  > I wonder what you think "greenspunning" actually is?
>
> Regardless of its exact definition, it's a derogatory term that
> suggests an inefficient, unmaintainable, unnecessary implementation
> of features built into another language.  Macros make Lisp pattern-
> matching libraries both efficient and maintainable, and ML's lack
> of macros makes these libraries necessary if one wants both macros
> and pattern matching.
>
>  >> I don't think the ML family is "much" more concise than Lisp
>  >> when you take macros into account.
>
>  > You believe that. Other people believe differently. How can you reach
>  > agreement? Certainly not by ad hominem attacks and attacking straw men
>  > (what, at the end of the day, the argument "he sells book" actually
>  > is.
>
> Straw man.
>
> No-one objects to selling books.  Only to trolling.
>
>  > And if I consider further, trying to contradict my lack of
>  > understanding of this argument
>
> I don't contradict your lack of understanding at all, Markus.
> I totally agree that you lack a basic understanding of Jon's
> trolling and what other people have been saying to you.
>
>  > by constructing a case against JH by some other route
>  > ("Greenspunning", "It's wrong than ML is more concise")
>  > is also a strawman, because it makes the "he sells books"
>  > argument not any more valid, not one iota).
>
> Obvious straw man, made even worse by appealing to the straw-man
> fallacy yourself.  It's Jon who's making the Greenspunning arguments,
> and no-one objects to selling books.  I think you're another troll.

And I think you're right.

0
Reply slobodan.blazeski (1459) 7/27/2007 9:35:51 AM

Markus E.L. wrote:
> Jon -- what do you mean by "not easy" here: Not easy in the current
> implementations or is callc somehow in conflict with the language
> structure itself? What I'm aiming at is the question wether a
> different runtime (with a different stack implementation like most
> scheme implementations I know of) would allow integrating callc to
> OCaml and/or Lisp.

That is possible, as you say, but getting decent performance out of an
implementation that uses a custom stack is likely to be difficult. If you
stick with an array-based representation then ordinary performance should
be good (you would need to allocate a huge array though) but callcc would
have to copy the whole array. If you switch to an immutable list-based
representation then ordinary code will be much slower (the GC will be
stressed a lot more, collecting stack frames) but there is no need to copy
the stack.

> On the other side, if that was not possible 
> (because callcc is somehow in conflict with the rest of the language
> definition) that would mean that there would be no efficient or
> straight forward compiler from Lisp and/or OCaml to Scheme, something
> I always considered doable, though perhaps not desirable.

There is no fundamental theoretical problem besides changing the stack to
make it persistent.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 9:43:34 AM

Dan Bensen wrote:
> I don't think a simple library counts as "Greenspunning".

Yet a Lisper coined the phrase to describe the reinvention of lists in C
code. A good pattern match compiler is thousands of lines of code, compared
to ~10 for a list.

> Macros make Lisp pattern-matching libraries both efficient...

That belief is contrary to all of the quantitative evidence objectively
gathered so far:

http://www.ffconsultancy.com/languages/ray_tracer/
http://www.lambdassociates.org/studies/study10.htm
http://groups.google.co.uk/group/comp.lang.lisp/msg/f47aa6043e79770e?hl=en&

> ML's lack of macros...

camlp4:

http://www.ocaml-tutorial.org/camlp4_3.10

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 10:12:21 AM

David Golden schrieb:
> Joachim Durchholz wrote:
> 
>> What, then, is a place?
>>
> http://www.lisp.org/HyperSpec/Body/sec_5-1-1.html
> 
> By example - "increment the second element of the array
> that is in b in an instance of structure s that is bound to a":
> (incf (aref (s-b a) 1))

Seems like it's essentially an lvalue, only you can provide an algorithm 
to pinpoint it instead of passing it around directly.
I.e. it's equivalent to a function returning an lvalue (with a very 
simple syntax).

> Perhaps not so relevant in a non-mutable/non-side-effecting context:

Well, in modern FPLs, anonymous functions are almost the same as 
expressions syntactically, so writing a function that returns an lvalue 
should be a snap in OCaml or SML.
Actually, the technique would be so straightforward that I wouldn't even 
name it.

Regards,
Jo
0
Reply jo427 (1164) 7/27/2007 10:14:15 AM

Joachim Durchholz wrote:
> Well, in modern FPLs, anonymous functions are almost the same as
> expressions syntactically, so writing a function that returns an lvalue
> should be a snap in OCaml or SML.
> Actually, the technique would be so straightforward that I wouldn't even
> name it.

You can even see it in my Minim interpreter.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 10:14:38 AM

>  > Regards -- Markus (Who think's that some of the participants in
>  > this slug fest should better their logic by reading e.g. here:
>  > http://www.nizkor.org/features/fallacies)
>
> Markus, I've already KF'd you, because I find your posts misleading
> and argumentative.  But since you went so far as to cite logical
> fallacies, I'll describe the fallacies that you've been commiting.
> Your main problem seems to be an inability to address comments
> without distorting them, which is classic trolling behavior.
>
>  >> Markus E Leypold wrote:
>  >>  > Actually I don't see:
>  >>  >  1. Jon didn't hype his book in this thread.
>  >>
>  >> First of all, Marcus, Jon's signature does advertise his book, so
>  >> he has directly advertised his book in this thread simply by posting
>  >> to it.
>
> Markus E.L. wrote:
>  > Oh I see. How bad.
>
> Straw man.
> http://www.nizkor.org/features/fallacies/straw-man.html
>
> I never said advertising was bad.  I only suggested that your
> statement was inaccurate, because Jon hypes OCaml and advertises
> his book.
>
>  >> As for "hyping", it's not necessary to promote the book directly.
>  >> It may be enough to draw programmers toward OCaml by making
>  >> comparisons that are unfairly biased against Lisp, which Jon
>  >> has been doing repeatedly.
>
>  > And pulling them to himself just by alienating them to Lisp.
>  > Don't be ridiculous. Jon is not the only OCaml developer around.
>
> Red herring.
> http://www.nizkor.org/features/fallacies/red-herring.html
>
> The question is not whether other OCaml developers post to the usenet,
> but whether Jon has been trolling.  He has been the only developer
> regularly making comparisons that are unfairly biased against Lisp.

It's the "unfair" actually that's under discussion. And I don't think
I've to defend my arguments against the allegation of them being
fallacies: I freely admit they are rhetoric, not more. To actaully
refute your "Jon is a troll" argument, it suffices to point out that
neither "he sells books" nor "he has a link to his book in his
signature" do constitute conclusive arguments in support of your
proposition.

I don't think I need to say more and the reference to
nizkor.org/features/fallacies doesn't wash, since were are not
discussing any more: Since when would I answer to non-arguments with
logic instead of just saying "step back, don't be ridiculous -- don't
you realize how far fetched you attempts to construct a case are?".

If you _really_ want to continue your "Jon is a troll" argument (and
from the responses I get as compared to the responses on Lisp
benchmarking in this thread I get the impression that perhaps more
people on c.l.l. are interested in branding JH as a troll than in
Lisp) -- if suggest we start again from the beginning: State your
proposition and than gather evidence in support. All that "he has
written a book", "he sells a book", "he has a link in his signature",
"somewhere [no reference!] he even admitted ..." is absolutely
inconclusive, not good for anything and to me suspiciously sounds like
a group of people is desperately groping for evidence to convict
somebody they consider already guilty.

If you all need kangaroo courts in c.l.l. to keep the quiet and free
of controversial posting: By all means continue. Without my further
participation of course, sicne I've already said most of what I had to
say.

On the other side I see an enforcement problem (c.l.l. is not
moderated AFAIK) and suggest you consider that -- assuming for the
moment, Jon really were a troll -- that the best cure against troll
has been so far to ignore them (see Xah Lee :-). Obviously there is no
sufficient majority for that in c.l.l which should give you and idea
how trollish JH probably is.

>  >> Markus, do you consider it "true and useful" to say that
>  >> pattern-matching libraries are "Greenspunning"?
>
>  > I think expresses very well, why Jon distains pattern matching
>  > libraries in Lisp and thinks that pattern matching belongs into
>  > the core language.  So indeed the hint 'Greenspun' does communicate
>  > the argument very concisly.
>
> Red herring.

I'm tempted to say <insult> here: I just explained to you, that I
don't know 'Greenspun' as a verb, so I'm not sure what it really means
-- and I explain. Of course I now get accused of "Red Herring". My
bad. Shouldn't explain.

> The question is not whether the term expresses a sentiment, but
> whether the sentiment is warranted.  I don't think a simple library
> counts as "Greenspunning".

Well, but obviously it's not so clear cut: The library provides
features, other FPs have already in the core language. Jon argued that
Grenspun's 10th rule applies. You argue "it doesn't count as ..." --
an argument where I still percieve that you take "greenspunning" as
negative or a kind of insult. Admittedly I don't know what to make of
it. Is the hint to Greenspuns 10th rule "wrong" in any way or
"useless"? Or what is the argument you're trying to build: AFAI
understood it was something on the lines of: Jon is a troll. To prove
that you have to disprove my statement that Jons contributions are
"true and useful". So you take on reply and try to prove it's
nonsense, wrong or insulting (I'm not sure what). I think you can the
fallacy there. I don't see were that should lead us to.

>
>  >> Do you think ML languages are "much more concise" than Lisp?
>
>  > Unfortunately I'm programming in ML languages rather than Lisp,
>  > preferrably in OCaml. So ... -- I'm certainly biased. Regarding
>  > pattern matching -- Yes, I think ML (and Haskell pattern matching is
>  > more concise than anything of that kind I have seen in Lisp so far,
>  > and certainly more than nesting of conditional statements.
>
> Red herring.

> We're not talking about the conciseness of pattern matching alone.
> We're talking about the overall conciseness of each language,
> based on pattern matching, macros, and all other features.

Not in this subthread. And not me with you, certainly. Jon's arguments
are useful and interesting, wether you like it or not, whereas your
shouting "Red Herring" at avery partial statement is not. Asking me,
wether "I find ... <whatever>" how that relates to the question what
Jon is, and I'm to bored and lazy now to look up THAT special fallacy,
but be assured: It is one: At least you're changing the topic.

Decide: Do you want to discuss Lisp with me? That was not how we
started and I've indicated that I'm probably not qualified and too
biased to be useful as an opponent regarding this question. I've never
decided against Lisp and for OCaml: It's just OCaml is good enough for
me, I don't have problem with the syntax, it is fast enough for me, it
has a useful type system and I met it at the time I needed it. There
you are. 

Or: Do you want to discuss about "Jon is a troll"? I alread said I
don't experience him like this and cannot see it so clear cut that his
statements are untrue or not useful. The example you brought so far is
unsuitable to discuss that point, because it's not clear wether it's
right or wrong and one example of a false or useless opinion or
statement wouldn't even support that a person is troll that is only
posting useless spam on usenet. Do we really need to continue this
topic? Your logic is flawed and that's it (and you're confusing the
question wether Jon is right with the question wether Jon is a troll:
Somthing you're not alone with: Other contributors to that thread
already have argued in the spirit of "I think he is wrong, so he is a
troll").


| > Humm... I still find your comparison loaded: you rule out the use of
| > libraries for pattern matching in Lisp. Why?

>
>  >> I don't think libraries and simple macros are Greenspunning
>  > I wonder what you think "greenspunning" actually is?

> Regardless of its exact definition, it's a derogatory term that
> suggests an inefficient, unmaintainable, unnecessary implementation
> of features built into another language.  

Well -- and how efficient IS pattern matching in Lisp? And if people
start to build their porgramming around pattern matching, don't you
think it makes a difference. I also noticed when quoting you
conveniently snipped the following piece of text from my last posting:

| In ML it also ties in rather nicely with the type system: In many
| cases the compiler will warn you about forgotten cases -- something
| I imagine the Lisp systems must have difficulties with owing to the
| dynamic type system.

> Macros make Lisp pattern-
> matching libraries both efficient and maintainable, and ML's lack
> of macros makes these libraries necessary if one wants both macros
> and pattern matching.

I don't see how ML's lack of macros makes any libraries in Lisp
necessary.

>
>  >> I don't think the ML family is "much" more concise than Lisp
>  >> when you take macros into account.
>
>  > You believe that. Other people believe differently. How can you reach
>  > agreement? Certainly not by ad hominem attacks and attacking straw men
>  > (what, at the end of the day, the argument "he sells book" actually
>  > is.

>
> Straw man.

No, it's not. It adresses a big issue in this thread: How people
discuss with each other and how they reach agreement: Some obviously
have decided that

   "why do you ..." "because he sells books" 

is a valid argument of some kind. It isn't and it won't ever become
(at least in a resonably rational community).

> No-one objects to selling books.  Only to trolling.

Which again is proven by "selling books"? Dan, if you got a quiet
moment, just go back to the post where I came into this thread (that
with the "because he sells books" quote). 

I'm not arguing pro/contra Lisp/OCaml or whatever. As I said: If I
think about it, I'm not qualified to do that and the arguments I hear
(_on the topic_, mind you) are not so obviously wrong or fallacious
that I could decide or see instantanously that a civiliced dispute is
unnecessary.

But I'm objecting to the way some people here communicate with others
-- and that includes you and this, your, post


>  > And if I consider further, trying to contradict my lack of
>  > understanding of this argument

> I don't contradict your lack of understanding at all, Markus.
> I totally agree that you lack a basic understanding of Jon's
> trolling and what other people have been saying to you.

Well, I see. I think that proves my point. Because I don't just take
your word for it (whatever), I'm bad and probably stupid (my "lack [of]
basic understanding of [...]  what other people have been saying to
you). Are you (are the others that have been trying to tell me) a
usenet god? Or doesn't the usually rule, that if you want somebody to
think you thought you have to convince them, also apply to you?

And what's more: My impression is that the Jon-Harrop-Opposition at
c.l.l. is a rather vocal minority with a lot of poison to spent. And
that IS my impression. You and the others will have to live with that,
because you just can't take it away.

>  > by constructing a case against JH by some other route
>  > ("Greenspunning", "It's wrong than ML is more concise")
>  > is also a strawman, because it makes the "he sells books"
>  > argument not any more valid, not one iota).
>
> Obvious straw man, made even worse by appealing to the straw-man
> fallacy yourself.  

Well, I regret, I don't see the straw man.

> It's Jon who's making the Greenspunning arguments,
> and no-one objects to selling books.  

No, no one. There is no wall, there are no wardens, there is no
prison, you're not here ... 

BTW: Did I say it was you making the "Greenspunning argument"
(whatever evil that might be, it certainly sounds mightily depraved)?

> I think you're another troll.

Aaah. The old "I don't like you, you're a troll" manoeuvre. A usenet
classic, indeed. Nice to meet you.

Yes, please plonk me and refrain from responding. :-)

I've spent too much time on this post anyway. Can't answer you at so
much length in future, but the basic front line should be clear (and
the basic strategies also have been tested, like yours of sprinkling
"Red Herring" and "Straw man" liberally into selective quoting of my
post -- perhaps I can even continue the discussion with myself in this
vein)

(Personal I think I'm fighting against kangaroo courts and for free
speech, but that is an aside for other readers only.)

Regards -- Markus
0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 10:25:39 AM

Andr� Thieme schrieb:
> That Lisp has all these parens has mainly two reasons.
> First: they organize code itself in trees, making it trivially 
> transformable.
> Translation into a syntax tree is not important anymore, because code
> already is one. Having so easy accessible macros comes from representing
> code inside one of the most flexible datastructures.

This argument applies to any kind of regular syntax.
Lisp could thrive with predefined operator precedence plus 
indentation-is-parentheses (plus parentheses for those cases where you 
still need them), have 90% less parentheses, 30% more code per page, and 
*still* be simple to process macrologically.

> But even if we ignore that there is another design descision:
> having functions that can take any number of arguments.
> To make that possible you need two tokens.

You can make that possible without the need for additional tokens.
Simply use currying.

> One might think: hey, why not making the first argument to a function
> call always the number of arguments that will follow?
> Then no parens are needed. Instead of (+ 1 2 3) we would say:
> + 3 1 2 3

Not a good idea anyway. You'd end up chasing number-of-arguments bugs.

> With the descision of allowing functions that take any number of
> arguments Lisp has the nice feature that packing data into a list before
> making it an argument is done by the compiler.
> (+ 1 2 3) instead of (+ (list 1 2 3))

OK, currying cannot handle that case; the Haskell equivalent of the 
above would be
   plus [1 2 3]

However, such lists are needed only in a few places in a program. I 
don't think that this case warrants special attention to make it easy - 
not if it constrains the design space elsewhere.

>> Code transformation is done by the compiler in Haskell.
>> Abstraction (i.e. new languages) is daily staple in Haskell. Sure, 
>> Haskell embedded languages cannot do fancy syntax, but if you're fine 
>> with frugal syntax, you define your embedded language simply as a set 
>> of HOFs to use.
> 
> You can do the same in Lisp by making things lazy.

Ah, but laziness cannot be efficiently implemented in Lisp.
Nor would that be very desirable in a language with mutation.

 > In Lisp it would be
> uglier than in Haskell because you would explicitily say
> (delay (+ 1 2 3)) and (force xyz).

The main difference is that modern non-Lisp FPLs leave out the outermost 
pair of parentheses :-)
(... and the parentheses at the outermost level between operators)

> And yes, I think with lazy evaluation Haskell comes much closer to what
> macros can do in a usable way than most other languages.

Then we agree here.

>  > All without macros...
> 
> Lisp could also do it. But it does not have to rely on lazyness.

You don't need laziness to get rid of most parentheses.
It's completely orthogonal to semantics.

> In Lisp you get very nice syntactical abstractions.
> All without lazyness...

Regards,
Jo
0
Reply jo427 (1164) 7/27/2007 10:31:31 AM

> development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus E.L.) writes:
>
>> Dan,
>> 
>> >  >>>> Jon Harrop escreveu:
>> >  >>>>> Pattern matching ... is the main reason why OCaml, SML,
>> >  >>>>> Haskell and F# are all much more concise than Common Lisp.
>> >
>> >  >>> Cesar Rabak wrote:
>> >  >>>> I still find your comparison loaded: you rule out the use
>> >  >>>> of libraries for pattern matching in Lisp. Why?
>> >
>> >  >> Dan Bensen escreveu:
>> >  >>> Because it sells books.
>> >
>> > Markus E Leypold wrote:
>> >  > Actually I don't see:
>> >  >  1. Jon didn't hype his book in this thread.
>> >
>> > First of all, Marcus, Jon's signature does advertise his book, so
>> > he has directly advertised his book in this thread simply by posting
>> > to it. 
>> 
>> Oh I see. How bad. If you follow my mail domain, you'll also find a
>> business web site (now somewhat out dated). Does that make me a spammer
>> too? And do you click on every link in signatures? I really don't see how
>> the word "hype" would apply to posting a link in a signature. And what
>> about www.prairienet.org/~dsb/? What about people having their their
>> company name in the sig?
>
> The sig is only a problem because of his other behaviour.  As I said

Behaviour? Perhaps just write to his teacher ... :-/. People, grow
up. This is usenet: The only way to enforce is not to respond. Since
c.l.l. obviously can't ignore JH's posts the problem AND there are
people who don't want them, this is a c.l.l. problem. And you will
have to live with it. And perhaps better not attack other people too,
who happen to defend Jon. And, last, to go back to the beginning of
these threads: No reason to bring your venom to c.l.f.

> before, his posts probably fit better for comp.lang.functional.  On the

Maybe. On the other side (without researching what Jon actaully
posted), I find it somehow doubtful that discussion of limits and
weaknesses of lisp won't have a place on c.l.l. In comparison:
Certainly I don't want to see discussions on the (suppossed or real)
weaknesses of GC and FP take place only at c.l.ada (they are biased),
but rather in c.l.f.

> other hand, I am reading comp.lang.lisp (no followups set there, so I
> probably won't read answers to this message).  

My rule is: You post accusations / judgements on people on group X,
you read my answer there. I've been ignoring the follow-ups in this
threads consistently, especially if people post from and to c.l.l. and
set f'up to c.l.f. That is the curse of crossposting.

Call me a troll. :-) You wouldn't be the first one.

> Maybe you can understand
> that I do not want to hear the continued promotion of OCaml and F# in a
> lisp newsgroup.  (And, BTW, it is often a very brain-dead promotion,
> because the guy deliberately refuses to understand other people arguments.)

My impression is, that there are two parties that don't want to
understand. I have seen enough instances of JH listening to arguements
that I wonder why the "problem" is so prevalent in c.l.l.

Regards -- Markus 

     ( Whom the style of the JH opposition alone already has convinced
       that the problem is not JH alone. )


0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 10:37:37 AM

>> I'm certain you can go and ask his provider to suspend his
>> access. Providers don't like spammers, I hear.
>> 
>
> That's probably why he bothers to supply bodies in his posts, as
> outlined by some helpful soul in
> http://groups.google.com/group/comp.lang.lisp/msg/7f66e71bdbcf0ffc

You have strange ideas about ROI in advertising. I'm sure for the time
he spents in writing up all thos usenet posts he acan earn enough
money to buy lot's of advertisement in places where it really matters
(as opposed to usenet). Search engine manipulation is also available
for cheaper.

Perhaps you all should latch on another conspiracy theory: Jon Harrop
as a (gasp!) camouflaged spammer (he even puts bodies in his posts,
not to be recognized!) doesn't sound too convincing.

Regards -- Markus






0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 10:44:22 AM


> 3. Jon often posts to c.l.l *only*  (i.e., without also posting to c.l.f.)

First time I hear somebody being critised for _not_ cross posting.

> 4. Jon's often posts about ocaml to c.l.l *only*.

You sure the word "Lisp" was totally absent from those posts? And they
were thread starters? Hm.

> Jon should post to c.l.f. about ocaml but he doesn't - why? Because
> comparatively few people read or post to c.l.f. and Jon's aim is to
> reach as many potential customers has possible. 

Don't you think the entrenched Lisp community is exactly that (customers) not?

And thanks for bringing all that to c.l.f. BTW: Does that qualify as
spam by your questionnaire? I can't decide from the top off my head.

Regards -- Markus




0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 10:48:51 AM


<...>
> Remember, the example as I gave it was to just to illustrate an effect
> of identifier lengths on perceived code length, comparing long-looking
<...>

I don't need (to remebember). I've not participating in the
discusssion per se but only criticising your style and manners.

> Are *you* going to assert the below Qi[1] and ocaml ML[1] are "the

As Dan Bensen, you're mixing up the questions 

 - what I think
 - wether Jon is right
 - wether Jon is a troll
 - and how you conduct your conflict with Jon

Some of them are only losely related to each other.

I'd even say: I'm not interested in your Qi/Lisp/ML comparison. I
don't usually decide on programming systems because they are faster
(or slower within certain limits) or because the programs are
shorter. Comprehensibility is not measured by key strokes I need to
enter a program. I type fast enough.

> same"? And then expect I dive into a childishly diversionary tarpit of
> explaining all differences, allowing "you" (imagining you were Jon) to

Now, I'm not Jon ...

> divert and prolong argument? 

.... and I'm not interested in your argument, but solely, sorry, your
childish attempts to provoke Jon.


Regards -- Markus
0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 10:56:26 AM


>> And that despite Rainer's attempt to carry the fight over to c.l.f ...
>
> That's a lie, Markus. 

How so? Did you really think after flagging Jon as troll at c.l.l
(which certainly goes deeper and is more personal than saying "that's
OT here") it would be without consequences to post Jon's contribution
here? Or WAS that an attempt to disturb the ant hill and see what
happens?

And I even, in response to the first reaction "don't bring your bar
room brawls to c.l.f" , defended your right to post it there.

I'm really ready to hear that that wasn't your intention and that a
well meant attempt on stimulating discussion failed, but ...

Regards -- Markus

0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 11:03:12 AM

> Believe what you want.  Do I really have to go through the last months of
> comp.lang.lisp to prove my fact?  Maybe you can tell me why his profile
>
> http://groups.google.de/groups/profile?enc_user=I_YUthUAAACWD_8VFKtRU42NeunWF-drfMq7BcOOnMpM9MYZ86CqoA&hl=en
>
> is so bad and shows more posts in comp.lang.lisp than everywhere else...

I see. Google profiles are practically a judgment from God? Or do they
just reflect that people (and people using Google as news reader at
that) don't agree with Jon?

Regards -- Markus

0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 11:06:39 AM

Dan Bensen schrieb:
>  >>>> Jon Harrop escreveu:
>  >>>>> Pattern matching ... is the main reason why OCaml, SML,
>  >>>>> Haskell and F# are all much more concise than Common Lisp.
> 
>  >>> Cesar Rabak wrote:
>  >>>> I still find your comparison loaded: you rule out the use
>  >>>> of libraries for pattern matching in Lisp. Why?
> 
>  >> Dan Bensen escreveu:
>  >>> Because it sells books.
> 
> Markus E Leypold wrote:
>  > Actually I don't see:
>  >  1. Jon didn't hype his book in this thread.
> 
> First of all, Marcus, Jon's signature does advertise his book, so
> he has directly advertised his book in this thread simply by posting
> to it.

Now you're exaggerating.
I actually had to look at Jon's last post to even notice that he had a 
URL to his book in the sig.

 > As for "hyping", it's not necessary to promote the book
> directly.  It may be enough to draw programmers toward OCaml by making
> comparisons that are unfairly biased against Lisp, which Jon has been
> doing repeatedly.

I think both sides are guilty of presenting things in a favorable light.

In fact this is a long-standing gripe that I have been having about the 
Lisp community. Disadvantages are discussed far more openly in other 
communities (e.g. the Haskell community is quite open about the 
advantages and disadvantages of laziness).

Not that I don't understand that. If you keep taking unfair flak for 
decades (literally!), such a stance can easily evolve and solidify into 
common consensus.

Oh, and there's another big difference. Most discussions about relative 
advantages and disadvantages evolve into matter-of-belief statements. 
Jon is far more down to facts than that: He's giving benchmarks, making 
himself open to critique; he's adapting the benchmarks in response to 
the critique; he's counting lines, characters, or tokens and arguing his 
choice of criteria rationally.
You can agree or disagree with his findings, but he never asks you to 
believe.
Few Lispers typically argue on that level. I'm not in any Lisp 
community, but those Lispers that I have come across elsewhere have a 
noticeable affinity to belief-based arguments (and are generally taken 
less seriously as a consequence).

If these observations are true and relevant, then Jon must indeed come 
across as a troll, since he doesn't accept the typical Lisper's code of 
conduct. However, I think it's the code of conduct that's more to blame. 
(OK, I'll also admit that Jon can be rather rude and tends to generalize 
his findings a bit more than I'm inclined to follow. I'm not sure 
whether that's his normal tone or was provoked by stubborn disbelief 
reactions from the Lisp community.)

>  >  2. That someone is working in a given subject area X and actually is
>  >     making money from it -- is that disqualifying him from making
>  >     useful and true statements on usenet?
> 
> Markus, do you consider it "true and useful" to say that pattern-
> matching libraries are "Greenspunning"?  Do you think ML languages
> are "much more concise" than Lisp?  I don't think those statements
> are either true or useful.

 From what I know, at least the second statement is true.
I don't know what "Greenspunning" is, but those pattern-matching 
libraries that I have seen weren't very well-designed; also, I doubt 
that a library can reap all the benefits that built-in pattern-matching 
can, though I'm unsure how much of that doubt is well-founded. In other 
words, I tend to the position that lack of pattern matching might be a 
reasonable criticism of Lisp.

 > I don't think libraries and simple macros
> are Greenspunning, and I don't think the ML family is "much" more
> concise than Lisp when you take macros into account.

I have seen some of the things that can be made concise in Haskell, and 
it was outright amazing.
(If Haskell could marshall thunks, I'd be programming in the language 
right now.)

My ability to assess the usefulness of macros is slightly limited. 
However, I'm having trouble with limiting what a macro can do. In 
principle, a macro can cause its parameters to be evaluated once, not at 
all, or an arbitrary number of times; it could do the evaluation at 
expansion time or at evaluation time.
If Lisp were pure, it wouldn't matter when exactly what is evaluated, 
but then Lisp wouldn't need macros anyway :-)
Oh, and with standard macros from the standard libraries, these problems 
usually don't happen - I'd assume that every macro has a clear 
description when it evaluates what parameter, or it's easy to look that 
up. The problems start to arise when people write their own macros. (And 
with standard macros where you just *think* you had understood its 
behavior, and overlooked some special case which comes back to bite you, 
possibly years after you learned to use that macro. Or when different 
vendors use slightly different interpretations of the standard and the 
code starts to break.)

Just an outsider's view, possibly totally irrelevant and off the mark.

Regards,
Jo
0
Reply jo427 (1164) 7/27/2007 11:11:22 AM

>>>>>> "M.E.L." == Markus E L <development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de> writes:
>
>   M.E.L.> In many cases the compiler will warn you about forgotten
>   M.E.L.> cases -- something I imagine the Lisp systems must have
>   M.E.L.> difficulties with owing to the dynamic type system.
>
> In Erlang (which is dynamically typed), the compiler warns about
> clauses that can never match, and a companion tool called Dialyzer
> (part of Erlang/OTP) does dataflow analysis on programs, 
> collecting type information, and warns about all sorts of things,
> such as unreachable code, calling a function with incompatible types,
> etc. Since the language is dynamic, even Dialyzer can't warn against
> forgotten cases -- there is no template from which to judge that,
> other than the derived signatures of the call sites. Thus, Dialyzer
> can often tell whether a function is calling another using a type
> that is not handled.

Yes, I thought that a dynamically typed language can get that feature
with a data flow analyzer -- therefore I wrote "difficulties" instaed
of "impossible", the choice of words was intentional. 

If I see it right, data flow analysis is tightly related to automatic
type derivation. Indeed I like the idea that one can get an untyped
language and the type systems as external tools to be applied at will
and where needed. I understood Qi to be exactly such a system. The
only problem I see, is, that typing also directs the compiler in
optimization and choosing data representations (or should/does in a
language like ML). I don't see a simple way to do that with
"pluggable" systems, so the runtime would have to be like the runtime
of Scheme and support dynamic types. That is perhaps not a problem, I
don't know, but it's one of the points where I could imagine such a
system to fail / become inefficient. But I might be wrong. There is
certainly much research still to be done and it's a pity that the
adoption of new and better languages in the industry (not your
company, certainly) is so glacial.

Regards -- Markus



0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 11:23:01 AM

> spare. So spammer could spent days finding examples that makes his
> views look better while the people who want to challenge his remarks
> have only minutes.

You certainly got a point here: I don't have so much time to correct
the bad manners of a certainly largish c.l.l group. So, after saying
my piece and getting the same non-sequitur answers a couple of times
("But don't you see, ... he IS a spammer/troll?") I'll have to do
something else. You people's minutes add up to hours of my time.

Regards -- Markus


0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 11:26:47 AM

> Markus E.L. wrote:
>> Jon -- what do you mean by "not easy" here: Not easy in the current
>> implementations or is callc somehow in conflict with the language
>> structure itself? What I'm aiming at is the question wether a
>> different runtime (with a different stack implementation like most
>> scheme implementations I know of) would allow integrating callc to
>> OCaml and/or Lisp.
>
> That is possible, as you say, but getting decent performance out of an
> implementation that uses a custom stack is likely to be difficult. 

May I contradict here? I thought, most of the Schemes have a decent
performance, even with callcc?

> There is no fundamental theoretical problem besides changing the stack to
> make it persistent.

Good :-).

Regards -- Markus

0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 11:29:56 AM

Chris Smith schrieb:
> Interestingly, one thing that IS true is that eager-evaluation pure 
> functional programs are actually asymptotically worse than alternatives 
> for some problems.

Any background information where I can read up on that?

Regards,
Jo
0
Reply jo427 (1164) 7/27/2007 11:30:44 AM


> Dan Bensen schrieb:
>> Markus E Leypold wrote:
>>  > Actually I don't see:
>>  >  1. Jon didn't hype his book in this thread.
>> First of all, Marcus, Jon's signature does advertise his book, so
>> he has directly advertised his book in this thread simply by posting
>> to it.
>
> Now you're exaggerating.
> I actually had to look at Jon's last post to even notice that he had a
> URL to his book in the sig.

Me too. What indeed was the reason for my reply.

> I think both sides are guilty of presenting things in a favorable light.

That's certainly true. But, of course, that (alone) doesn't make people trolls
or spammers.

> In fact this is a long-standing gripe that I have been having about
> the Lisp community. Disadvantages are discussed far more openly in
> other communities (e.g. the Haskell community is quite open about the
> advantages and disadvantages of laziness).

That is exactly the impression I've been forming recently. Of course
I'm not often around at c.l.l. or other Lispish places, so I won't
know. 


<... and the rest ...>

All very true. :-)

Regards -- Markus (who's been posting too much today).

0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 11:36:58 AM

Markus E.L. escreveu:
> Dan,
[snipped]

> Regards -- Markus
> 
> (Who think's that some of the participants in this slug fest should
> better their logic by reading e.g. here:
> http://www.nizkor.org/features/fallacies)
> 
Markus,

It interesting yourself sent this link. It seems that bored people could 
easily maje a table for each of your recent post agains one of the 
fallacies described in your reference.
0
Reply csrabak (393) 7/27/2007 11:52:46 AM

Google profiles are not judgement of god but they could give you a
good hint especially when the number of reviews are quite high for
example I found only 3 lispers who exceed 100 reviews (I didn't
searched very hard)

Pascal Bourguignon  439 / 4 stars

0
Reply slobodan.blazeski (1459) 7/27/2007 12:13:41 PM

> Markus E.L. escreveu:
>> Dan,
> [snipped]
>
>> Regards -- Markus
>> (Who think's that some of the participants in this slug fest should
>> better their logic by reading e.g. here:
>> http://www.nizkor.org/features/fallacies)
>>
> Markus,
>
> It interesting yourself sent this link. It seems that bored people
> could easily maje a table for each of your recent post agains one of
> the fallacies described in your reference.

If you think so. But I think that would rather indicate that you
didn't get my point (which was not (a) perticipating in the Lisp
vs. OCaml discussion nor in disproving arguments regarding "Jon is a
Spammer" already made, but rather pointing out bad manners and that
there are no arguments (ao at least there were no arguments, so there
is no disproving them)).

Regards -- Markus


0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 12:14:19 PM

Joachim Durchholz wrote:
> In fact this is a long-standing gripe that I have been having about the
> Lisp community. Disadvantages are discussed far more openly in other
> communities (e.g. the Haskell community is quite open about the
> advantages and disadvantages of laziness).

Indeed, and this is precisely what concerns me. The Lisp community have
evolved a variety of stock responses designed to make Lisp look good that
are flawed in subtle ways. It takes quite some effort to figure out why
they are wrong and I think it is a real shame that so many people new to
functional programming end up wasting their time with Lisp when they could
be so much more productive using one of the modern FPLs.

This is exactly the same situation that scientific creationists have wiggled
into, particularly in the US. They say "evolution is a myth" and cite an
enormous number of pseudo-scientific reasons trying to undermine the theory
of evolution. That is actually a more interesting debate because the
responses of the scientific creationists has actually evolved over time.
Anyway, I digress.

First, you'll notice that Lispers only ever compare Lisp to Java. Comparing
to OCaml, Haskell or even C# is strictly prohibited on c.l.l. My ray tracer
elucidates why:

  http://www.ffconsultancy.com/languages/ray_tracer/results.html

Java is the only mainstream language that is as slow and verbose as Lisp.

When arguing with C programmers they used to quote Greenspun's Tenth Rule:

  "Any sufficiently complicated C program contains an ad-hoc, ill-
specified, slow, bug-ridden reimplementation of half of Common Lisp."

particularly with regard to the reimplementation of the list data structure
in C programs. Yet they disregard pattern matching (a core feature of all
modern FPLs) as something that they can trivially lash together (ad-hoc)
without saying exactly what it will do (ill-specified), disregarding the
overwhelming quantitative evidence of bad performance (slow) or having
studied the static verification of patterns (bug-ridden) or even caring
that it is not usefully encompassing (only half of ML).

This isn't so bad. But when you consider the depth and breadth of the
misinformation spread by the Lisp community it is really quite disturbing.
I think it is time to bury some of these myths.

A Lisper once wrote a paper on Lisp, comparing it only to Java:

  http://p-cos.net/documents/dynatype.pdf

The author can say "Lisp is better than Java", which is fine. But he can't
say:

  "However, statically typed languages require programmers to deal with all
methods of an interface at once..." -- page 3.

Just a simple mistake I thought. So I wrote to him, clarifying the mistake,
giving a counter example written in OCaml and explaining that inference
solved that problem many years ago. I expected the paper to be altered but,
instead, it was published and I received the response:

  "Thanks for your interest in improving that paper, but at the moment I  
have no intention to make any changes to it."

Take from that what you will.

> From what I know, at least the second statement is true.
> I don't know what "Greenspunning" is, but those pattern-matching
> libraries that I have seen weren't very well-designed; also, I doubt
> that a library can reap all the benefits that built-in pattern-matching
> can, though I'm unsure how much of that doubt is well-founded.

We've been gathering evidence for some time and it all agrees with your
assertion. Lisp can't support pattern matching in the generically-useful
way that SML, OCaml, Haskell and F# already do and pattern matchers written
in Lisp remain slower.

> My ability to assess the usefulness of macros is slightly limited.
> However, I'm having trouble with limiting what a macro can do. In
> principle, a macro can cause its parameters to be evaluated once, not at
> all, or an arbitrary number of times; it could do the evaluation at
> expansion time or at evaluation time.

A macro is simply a very rudimentary form of term rewriter and they are of
limited utility in any language. OCaml's camlp4 macros handle arbitrary
lazy streams, designed to be token streams, and provide an extensible form
of pattern matching. In Lisp, macros are restricted to handling only
s-exprs.

Doing any significant term rewriting without a pattern matcher is seriously
tedious.

Here is another example I recently stumbled upon. Take this code from
Maxima:

(defun bessel-k-simp (exp ignored z)
  (declare (ignore ignored))
  (let ((order (simpcheck (cadr exp) z))
        (rat-order nil))
    (let* ((arg (simpcheck (caddr exp) z)))
      (cond ((and (>= (signum1 order) 0) (bessel-numerical-eval-p order
arg))
             ;; A&S 9.6.6
             ;; K[-v](x) = K[v](x)
             (bessel-k (abs (float order)) (complex ($realpart arg) ($imagpart
arg))))
            ((mminusp order)
             ;; A&S 9.6.6
             ;; K[-v](x) = K[v](x)
             (resimplify (list '(%bessel_k) `((mtimes) -1 ,order) arg)))
            ((and $besselexpand
                  (setq rat-order (max-numeric-ratio-p order 2)))
             ;; When order is a fraction with a denominator of 2, we
             ;; can express the result in terms of elementary
             ;; functions.
             ;;
             ;; K[1/2](z) = sqrt(2/%pi/z)*exp(-z) = K[1/2](z)
             (bessel-k-half-order rat-order arg))
            (t
             (eqtest (list '(%bessel_k) order arg)
                     exp))))))

and translate it into any language with pattern matching. Note that the
pattern matches are actually written in the Lisp as comments but the
authors never bothered to pull in a pattern matching library or Greenspun
one themselves.

There is 84kLOC of such code in Maxima. How much shorter and faster would it
be if it were represented in terms of pattern matching? As the Lispers
always say, it is theoretically possible to do a good job but...

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 12:59:07 PM

Joachim Durchholz <jo@durchholz.org> writes:

> Lisp could thrive with predefined operator precedence plus
> indentation-is-parentheses (plus parentheses for those cases where you
> still need them), have 90% less parentheses, 30% more code per page,
> and *still* be simple to process macrologically.

It has been done -- would you claim that Dylan is thriving?

>> making it an argument is done by the compiler.
>> (+ 1 2 3) instead of (+ (list 1 2 3))
>
> OK, currying cannot handle that case; the Haskell equivalent of the
> above would be
>   plus [1 2 3]
>
> However, such lists are needed only in a few places in a program. I
> don't think that this case warrants special attention to make it easy
> - 
> not if it constrains the design space elsewhere.

Whether you use them in a few places or a lot depends on your
programming style, which is shaped by the languages you have used in
the past.  I would be more careful with making claims like this one.

>>> Code transformation is done by the compiler in Haskell.
>>> Abstraction (i.e. new languages) is daily staple in Haskell. Sure,
>>> Haskell embedded languages cannot do fancy syntax, but if you're
>>> fine with frugal syntax, you define your embedded language simply
>>> as a set of HOFs to use.
>>
>> You can do the same in Lisp by making things lazy.
>
> Ah, but laziness cannot be efficiently implemented in Lisp.

Why?  What is "efficient" enough for you?  Lazyness for part of your
program is easy to implement, and is pretty efficient.  Of course it
will not be as efficient as Haskell, where lazyness is integrated into
the whole language.  However, lazyness is not the holy grail, it makes
a lot of sense if you can write your algorithm more simply and a lot
of the stuff doesn't get evaluated, but it can be a curse if you know
that 99% of operations you code need to be evaluated anyway.  Most of
the time, it doesn't make a whole lot of difference in performance.
And I have seen Haskellers fight the language to get non-lazy
evaluation.

Tamas
0
Reply tkpapp (975) 7/27/2007 12:59:49 PM

Markus E.L. escreveu:
>> development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus E.L.) writes:
[snipped]

> 
> Behaviour? Perhaps just write to his teacher ... :-/. People, grow
> up. This is usenet: The only way to enforce is not to respond. Since
> c.l.l. obviously can't ignore JH's posts the problem AND there are
> people who don't want them, this is a c.l.l. problem. And you will
> have to live with it. And perhaps better not attack other people too,
> who happen to defend Jon. And, last, to go back to the beginning of
> these threads: No reason to bring your venom to c.l.f.

Hey man! How inconsistent are willing to go? Your argument: "People, 
grow up. This is usenet:" _But_ if people respond to Jon's crossposted 
posts you childly complain: "No reason to bring your venom to c.l.f."

What's the e-address of the teacher of yours?

> 
>> before, his posts probably fit better for comp.lang.functional.  On the
> 
> Maybe. On the other side (without researching what Jon actaully
> posted), I find it somehow doubtful that discussion of limits and

Which, brings to the kernel of reason people starts to find evidence 
your trolling as well. . .

[snipped]

> Call me a troll. :-) You wouldn't be the first one.

So your behaviour is recurrent...

> 
>> Maybe you can understand
>> that I do not want to hear the continued promotion of OCaml and F# in a
>> lisp newsgroup.  (And, BTW, it is often a very brain-dead promotion,
>> because the guy deliberately refuses to understand other people arguments.)
> 
> My impression is, that there are two parties that don't want to
> understand. I have seen enough instances of JH listening to arguements
> that I wonder why the "problem" is so prevalent in c.l.l.

JH interest in 'listening' arguments to c.l.l is another very loaded 
assertion of yours. He's fishing here all the rebuttals c.l.l 
gratuitously offer him. What uses he makes of them is OT in this discussion.


0
Reply csrabak (393) 7/27/2007 1:04:10 PM

Joachim Durchholz wrote:
> Lisp could thrive with predefined operator precedence...

I disagree. The problems with Lisp run far deeper than syntactic issues.
Having such an archaic syntax forced upon you is one of the main reasons
people never bother starting with Lisp (poor performance is the other). But
Lisp lacks so many features that people take forgranted now. It just isn't
going anywhere.

> Ah, but laziness cannot be efficiently implemented in Lisp...

As Haskell has shown, laziness cannot be implemented efficient at all.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 1:06:06 PM

Markus E.L. wrote:

> You have strange ideas about ROI in advertising.

I'm not saying I think it's particularly effective or smart advertising-
though Jon likes it.  
http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/68e2aa891dbbf1b
"We'll concentrate on releasing free content on our website and
referencing it from news articles instead, as this is much more
productive."

(There was I think a more direct admission, IIRC when Harrop was 
responding to Ken Tilton somewhere, that's just the first I found when I 
wasted some lunchtime searching, spending much time reading hundreds of
Harrop and Tilton posts is not exactly appealing)

> he spents in writing up all thos usenet posts

His inflaming and restarting old and well-explored arguments greatly
reduces any intellectual effort he would require to write up, and of
course there's simple direct cut/paste reuse of content, sometimes
only apparent if you encounter Jon in multiple fora.


0
Reply david.golden (499) 7/27/2007 1:10:22 PM

 > Dan Bensen schrieb:
 >> First of all, Marcus, Jon's signature does advertise his book, so
 >> he has directly advertised his book in this thread simply by posting
 >> to it.

Joachim Durchholz wrote:
 > Now you're exaggerating.

A little bit, but it's hard to be both exact and concise.

 >> As for "hyping", it's not necessary to promote the book
 >> directly.  It may be enough to draw programmers toward OCaml by
 >> making comparisons that are unfairly biased against Lisp, which
 >> Jon has been doing repeatedly.

 > I think both sides are guilty of presenting things in a
 > favorable light.

Yes, I agree with you.  The only defense I can offer is that
Lispers usually stay in their own back yard.

 > Oh, and there's another big difference. Most discussions about
 > relative advantages and disadvantages evolve into matter-of-belief
 > statements.  Jon is far more down to facts than that: He's giving
 > benchmarks, making himself open to critique; he's adapting the
 > benchmarks in response to the critique; he's counting lines,
 > characters, or tokens and arguing his choice of criteria rationally.

I'm getting tired of this thread, Joachim, so I'm not going to answer
in depth, but benchmarks don't address RAD, hot-loading code, and other
dynamic issues.  It's not fair to obsess over runtime performance in a
Lisp forum, because Lisp trades runtime optimization for many other
things.  Also, comments like
 >> Thats true, they teaching us Lisp on our university...
 >I really hope they teach you some good languages as well...
are insults, not facts.

 >> Markus, do you consider it "true and useful" to say that pattern-
 >> matching libraries are "Greenspunning"?  Do you think ML languages
 >> are "much more concise" than Lisp?  I don't think those statements
 >> are either true or useful.

 > From what I know, at least the second statement is true.
 > I don't know what "Greenspunning" is, but those pattern-matching
 > libraries that I have seen weren't very well-designed;

I don't know how good they are, but they can be fixed or replaced
if necessary.  Lisp already has excellent iteration and object systems
implemented as libraries.

 > My ability to assess the usefulness of macros is slightly limited.
 > However, I'm having trouble with limiting what a macro can do.
 > In principle, a macro can cause its parameters to be evaluated once,
 > not at all, or an arbitrary number of times; it could do the
 > evaluation at expansion time or at evaluation time.

No, macros are always called at expansion time, and they never evaluate
their arguments.  The only thing that evaluates expressions at eval time
is the code returned by the macro.

 > The problems start to arise when people write their own macros.

That depends on the individual.  Macros are very powerful, and in
experienced hands, they're plenty safe.

 > Just an outsider's view, possibly totally irrelevant and off the mark.

Always welcome. :)

-- 
Dan
www.prairienet.org/~dsb/
0
Reply randomgeek (299) 7/27/2007 1:15:11 PM

> Lisp could thrive with predefined operator precedence plus 
> indentation-is-parentheses 

Your opinion that such lispoids thrive is just not borne out by
history - Dylan, SRFI-49, etc.  

0
Reply david.golden (499) 7/27/2007 1:22:09 PM

Jon Harrop wrote:

> A Lisper once wrote a paper on Lisp, comparing it only to Java:
> 
>   http://p-cos.net/documents/dynatype.pdf

....which would be me.

> The author can say "Lisp is better than Java", which is fine.

I don't say that in that paper. More specifically, I am not advocating 
Lisp or Scheme in that paper at all.

> But he can't say:
> 
>   "However, statically typed languages require programmers to deal with all
> methods of an interface at once..." -- page 3.
> 
> Just a simple mistake I thought. So I wrote to him, clarifying the mistake,
> giving a counter example written in OCaml and explaining that inference
> solved that problem many years ago.

Quoting that sentence out of context is a misrepresentation of the 
paper. I state the following very clearly in the introduction:

"This paper mainly focuses on shortcomings in Java (again, because of 
the workshop theme) which is only one example of a statically typed 
programming language. There are others that may have different and 
actually better solutions by default. But I hope this serves as a good 
starting point for a more objective analysis of an otherwise usually 
very heatedly discussed topic."

> I expected the paper to be altered but,
> instead, it was published and I received the response:
> 
>   "Thanks for your interest in improving that paper, but at the moment I  
> have no intention to make any changes to it."
> 
> Take from that what you will.

The main reason is lack of time. Since the paper is very clearly 
presented as experimental work, and is in no way misleading about its 
actual merits, I see no reason to change or withdraw it. It has indeed a 
provocative tone, but that's because the workshop to which I submitted 
it asked for provocative position statements.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/27/2007 1:29:46 PM

> Markus E.L. escreveu:
>>> development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus E.L.) writes:
> [snipped]
>
>> Behaviour? Perhaps just write to his teacher ... :-/. People, grow
>> up. This is usenet: The only way to enforce is not to respond. Since
>> c.l.l. obviously can't ignore JH's posts the problem AND there are
>> people who don't want them, this is a c.l.l. problem. And you will
>> have to live with it. And perhaps better not attack other people too,
>> who happen to defend Jon. And, last, to go back to the beginning of
>> these threads: No reason to bring your venom to c.l.f.
>
> Hey man! How inconsistent are willing to go? Your argument: "People,
> grow up. This is usenet:" _But_ if people respond to Jon's crossposted
> posts you childly complain: "No reason to bring your venom to c.l.f."
>
> What's the e-address of the teacher of yours?

Want to learn the technique? :-).

>>> before, his posts probably fit better for comp.lang.functional.  On the
>> Maybe. On the other side (without researching what Jon actaully
>> posted), I find it somehow doubtful that discussion of limits and
>
> Which, brings to the kernel of reason people starts to find evidence
> your trolling as well. . .

Yes, I can see that. C.l.l. is for gloryfiying Lisp. Nothing else. And
people who find that strange, are trolls. 

> [snipped]
>
>> Call me a troll. :-) You wouldn't be the first one.
>
> So your behaviour is recurrent...

Only rarely and only with an audience lacking insight or self
critique. Never mind. if you and your companions don't understand the
problem you yourself are (probably even to yourself and your own
goals), I can't help it. But commiseration from my side is rather
limited: If Jon is trolling (which I'm not intrested to judge) you
certainly seem to earn it.

:-)

>>> Maybe you can understand
>>> that I do not want to hear the continued promotion of OCaml and F# in a
>>> lisp newsgroup.  (And, BTW, it is often a very brain-dead promotion,
>>> because the guy deliberately refuses to understand other people arguments.)
>> My impression is, that there are two parties that don't want to
>> understand. I have seen enough instances of JH listening to arguements
>> that I wonder why the "problem" is so prevalent in c.l.l.
>
> JH interest in 'listening' arguments to c.l.l is another very loaded
> assertion of yours. He's fishing here all the rebuttals c.l.l
> gratuitously offer him. What uses he makes of them is OT in this
> discussion.

Is that assessment based on irrefutable facts or just on
_interpretation_?

Some of you people from the beat-JH-faction are rather
unrelaxed. Instead of ignoring him (if he was a troll that would be
your only practical option) you just insist on the rest of the world
sharing your assessment. And then you go to war with the people who
don't. I don't think that will really yield the intended result,
always supposing the goal is peace and harmony in c.l.l. and not war
against <whomever>.

But never mind: You are welcome to your community. Jon, in my opinion
is not a spammer (is not outside c.l.l.) but certainly a fool trying
to talk to such a self contained community as c.l.l. seems to be: The
effort is ill spent, and it's hardly thinkable that the resulting
flame wars will get him any customers there (if that should be the
purpose), quite the opposite.

Jon: As far as I'm concerned, You're always welcome to compare Lisp
against whatever at c.l.f. I think the various differences between
implementations of FPLs and the tradeoffs (historical or necessary)
are on topic in c.l.f. Im not speaking for the whole of c.l.f.

My request to Mark Tarver: Wouldn't the benchmarking rather belong to
c.l.f instead of being cross posted to both groups? It totally belongs
to c.l.f but Lispers might take offence at the presence of other
languages in the benchmark and perhaps also any discussions resulting
from that. On the other side interested parties can always subscribe
to c.l.f which hasn't got so much traffic.

Thanks for listening to all concerned.

Regards -- Markus


0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 1:37:01 PM

> Google profiles are not judgement of god but they could give you a
> good hint especially when the number of reviews are quite high for
> example I found only 3 lispers who exceed 100 reviews (I didn't
> searched very hard)


Meaning, there are hardly good Lispers, only bad ones (JH). What does
that say to us about the way Google profiles are used? And the
validity to use them as a measure of someones trollishness?

(BTW: I _am_ sure, if Andrew Tanenbaum would pots on Usenet, I'm sure
you could get him voted down to hell in almost no time: He doesn't
"suffer fools gladly" as he says himself and there are a lot of
Linux-tru-only fan boys around that would not understand a word he is
saying, but that he is disqualifying Linux.

Regards -- Markus (Who's been using and enjoying Linux for years: But
I'm against irrational beliefs, so ...)

PS: Care to quote my original articles you're answering to? Usenet is
    not a forum and not Google Groups and it's considered good
    netiquette to provide some context.



0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 1:42:27 PM

> And I have seen Haskellers fight the language to get non-lazy
> evaluation.
>

I've also seen MLers and Lispers and Schemers writing lots of
additional notation to get lazy evaluation. The question mostly is,
which should be the default (lazy or eager) and what are the
respective tradeoffs of this decisions (say purity + possibility of
eq. reasoning vs. a generela impact on efficiency or something like
that)

A single observation has no power of proof in this regard.


Regards -- Markus

0
Reply development-2006-8ecbb5cc8aREMOVETHIS (1447) 7/27/2007 1:46:10 PM

Just curiosity here. I'm an Ocaml noob, and I've tried lisp (and loved
it!). If I understood correctly, macros in lisp can be expanded at
"runtime", so the output of macros can be influenced by user input,
right? If I understood correctly, this feature can be used also to
make some kind of optimization, specializing the code for that
particular user input (useful if the specialized code runs much faster
and the time gained is more than the time spent in compiling the
form).
Am I right?
Now my question is: can I do something like this in Ocaml (and
ocamlp4) ?

0
Reply laynor (7) 7/27/2007 1:47:09 PM

laynor@gmail.com wrote:

> Am I right?

Yes, in short.

> Now my question is: can I do something like this in Ocaml (and
> ocamlp4) ?

Well, MetaOCaml might be most interesting for you:
http://www.metaocaml.org/

0
Reply david.golden (499) 7/27/2007 1:52:01 PM

Kent M Pitman <pitman@nhplace.com> writes:
>whitespace characters, allowing one to write (a,b,c) meaning (a b c).

  The classic notation used commas. 

  The commas can still be seen in the original paper on Lisp:

http://www-formal.stanford.edu/jmc/recursive.html

  According to what I remember to have read about it, a list
  without commas appeared for the first time when a defective
  printer would not print commas. People reportedly then
  discovered that they liked this.

0
Reply ram (2828) 7/27/2007 2:20:17 PM

Jon Harrop <jon@ffconsultancy.com> writes:
>As Haskell has shown, laziness cannot be implemented efficient at all.

http://neilmitchell.blogspot.com/2007/07/making-haskell-faster-than-c.html

0
Reply ram (2828) 7/27/2007 2:37:36 PM

Tamas Papp schrieb:
> Joachim Durchholz <jo@durchholz.org> writes:
> 
>> Lisp could thrive with predefined operator precedence plus
>> indentation-is-parentheses (plus parentheses for those cases where you
>> still need them), have 90% less parentheses, 30% more code per page,
>> and *still* be simple to process macrologically.
> 
> It has been done -- would you claim that Dylan is thriving?

If Dylan doesn't thrive, that might have any number of reasons.
(Including unavailability of editors that can't properly block-indent, 
NIY syndrome, and a couple of others.)

>>> making it an argument is done by the compiler.
>>> (+ 1 2 3) instead of (+ (list 1 2 3))
>> OK, currying cannot handle that case; the Haskell equivalent of the
>> above would be
>>   plus [1 2 3]
>>
>> However, such lists are needed only in a few places in a program. I
>> don't think that this case warrants special attention to make it easy
>> - 
>> not if it constrains the design space elsewhere.
> 
> Whether you use them in a few places or a lot depends on your
> programming style, which is shaped by the languages you have used in
> the past.  I would be more careful with making claims like this one.

Well, what I have seen here and elsewhere surely had a *lot* of parentheses.

>>>> Code transformation is done by the compiler in Haskell.
>>>> Abstraction (i.e. new languages) is daily staple in Haskell. Sure,
>>>> Haskell embedded languages cannot do fancy syntax, but if you're
>>>> fine with frugal syntax, you define your embedded language simply
>>>> as a set of HOFs to use.
>>> You can do the same in Lisp by making things lazy.
>> Ah, but laziness cannot be efficiently implemented in Lisp.
> 
> Why?  What is "efficient" enough for you?  Lazyness for part of your
> program is easy to implement, and is pretty efficient.  Of course it
> will not be as efficient as Haskell, where lazyness is integrated into
> the whole language.

Exactly.

> However, lazyness is not the holy grail,

Nor do I think it is.
I was just responding to the claim that "you can do the same in Lisp by 
making things lazy". I don't think that would be practical due to the 
overhead.
Hey, it's even difficult to get it efficient enough for day-to-day use 
in Haskell. Haskell run-time systems are specifically geared towards 
lazy evaluation (Google for "tagless spineless machine"), and Haskell 
compilers do a *lot* of strictness analysis to get rid of lazy 
evaluation wherever possible, which is massively aided by static typing.

Nothing of this is possible in Lisp (some of it not even desirable to 
keep the language useful for other goals).
So I conclude that "making things lazy to get it to work" isn't really 
an option - unless that laziness is controlled tightly and applied 
sparingly, that is, but that's not exactly how you'd do an embedded 
domain-specific language.

Note that this all is beside the point anyway. You don't need lazy 
evaluation to chain up HOFs, that's possible in a strict language as 
well (and hence in Lisp, too).
Sorry for not noticing the bigger context when reading the "by making 
things lazy" sentence.

 > it makes
> a lot of sense if you can write your algorithm more simply and a lot
> of the stuff doesn't get evaluated, but it can be a curse if you know
> that 99% of operations you code need to be evaluated anyway.  Most of
> the time, it doesn't make a whole lot of difference in performance.
> And I have seen Haskellers fight the language to get non-lazy
> evaluation.

I have seen people in other languages fight strictness (but, of course, 
attributing the problems to other things because everybody accepts 
strictness as a given). For example, everybody is accepting tons of 
contortions when all that you want to write down is "forall natural 
numbers, do so-and-so until condition this-and-that arises". Easy with 
laziness, contortious with strictness because you can't map the "forall 
natural numbers" part to a language construct directly - but people 
don't see it as a contortion, they just see it as how things are (if 
they think about it at all).

To do a real comparison, you'd probably need to train nonprogrammers 
both approaches in parallel.

Regards,
Jo
0
Reply jo427 (1164) 7/27/2007 2:57:03 PM

laynor@gmail.com wrote:
> Now my question is: can I do something like this in Ocaml (and
> ocamlp4) ?

Yes. You can write camlp4 macros that read arbitrary input and generate
OCaml code. In particular, you can write camlp4 macros that read an
extended form of OCaml (by extending camlp4's built-in OCaml parser).

If you want to do run-time code generation and compilation then you can
either use dynamic linking or MetaOCaml.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 3:02:53 PM

Tamas Papp wrote:
> Joachim Durchholz <jo@durchholz.org> writes:
> 
>> Lisp could thrive with predefined operator precedence plus
>> indentation-is-parentheses (plus parentheses for those cases where you
>> still need them), have 90% less parentheses, 30% more code per page,
>> and *still* be simple to process macrologically.
> 
> It has been done -- would you claim that Dylan is thriving?
> 
>>> making it an argument is done by the compiler.
>>> (+ 1 2 3) instead of (+ (list 1 2 3))
>> OK, currying cannot handle that case; the Haskell equivalent of the
>> above would be
>>   plus [1 2 3]
>>
>> However, such lists are needed only in a few places in a program. I
>> don't think that this case warrants special attention to make it easy
>> - 
>> not if it constrains the design space elsewhere.
> 
> Whether you use them in a few places or a lot depends on your
> programming style, which is shaped by the languages you have used in
> the past.  I would be more careful with making claims like this one.
> 
>>>> Code transformation is done by the compiler in Haskell.
>>>> Abstraction (i.e. new languages) is daily staple in Haskell. Sure,
>>>> Haskell embedded languages cannot do fancy syntax, but if you're
>>>> fine with frugal syntax, you define your embedded language simply
>>>> as a set of HOFs to use.
>>> You can do the same in Lisp by making things lazy.
>> Ah, but laziness cannot be efficiently implemented in Lisp.
> 
> Why?  What is "efficient" enough for you?  Lazyness for part of your
> program is easy to implement, and is pretty efficient.  Of course it
> will not be as efficient as Haskell, where lazyness is integrated into
> the whole language.  However, lazyness is not the holy grail, it makes
> a lot of sense if you can write your algorithm more simply and a lot
> of the stuff doesn't get evaluated, but it can be a curse if you know
> that 99% of operations you code need to be evaluated anyway.  Most of
> the time, it doesn't make a whole lot of difference in performance.
> And I have seen Haskellers fight the language to get non-lazy
> evaluation.
> 
> Tamas

Lazyness is also useful for separation of concerns.
read a file as if it was slurped entirely, process it as if it was fully 
available in memory, write the result as if they were all processed...
But do it in constant space. And no need for complex interleaving code.

I think that's pretty nice !

Sacha
0
Reply none6154 (92) 7/27/2007 3:03:28 PM

Stefan Ram wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>>As Haskell has shown, laziness cannot be implemented efficient at all.
> 
> http://neilmitchell.blogspot.com/2007/07/making-haskell-faster-than-c.html

Read the first comment:

  "Why not try writing a C implementation of the program requirements that's
actually fast?"

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 3:06:33 PM

Joachim Durchholz wrote:
> Chris Smith schrieb:
> > Interestingly, one thing that IS true is that eager-evaluation pure
> > functional programs are actually asymptotically worse than alternatives
> > for some problems.
>
> Any background information where I can read up on that?

http://web.comlab.ox.ac.uk/oucl/work/geraint.jones/morehaste.html

Should be a good start; it has links to both the paper describing the
problem with pure-eager languages, and one that shows pure-lazy
languages can match impure languages on the given problem. I'm not
sure if there's been additional research in this area or not.

0
Reply dan.doel (26) 7/27/2007 3:09:57 PM

Jon Harrop wrote:
> Joachim Durchholz wrote:
>> Lisp could thrive with predefined operator precedence...
> 
> I disagree. The problems with Lisp run far deeper than syntactic issues.
> Having such an archaic syntax forced upon you is one of the main reasons
> people never bother starting with Lisp (poor performance is the other). But
> Lisp lacks so many features that people take forgranted now. It just isn't
> going anywhere.
> 

There you go again =)

>> Ah, but laziness cannot be efficiently implemented in Lisp...
> 
> As Haskell has shown, laziness cannot be implemented efficient at all.
> 

As ruby and python have shown, programmers are only motivated by efficiency.

Sacha
0
Reply none6154 (92) 7/27/2007 3:11:16 PM

Dan Bensen schrieb:
>  > Oh, and there's another big difference. Most discussions about
>  > relative advantages and disadvantages evolve into matter-of-belief
>  > statements.  Jon is far more down to facts than that: He's giving
>  > benchmarks, making himself open to critique; he's adapting the
>  > benchmarks in response to the critique; he's counting lines,
>  > characters, or tokens and arguing his choice of criteria rationally.
> 
> I'm getting tired of this thread, Joachim, so I'm not going to answer
> in depth, but benchmarks don't address RAD, hot-loading code, and other
> dynamic issues.  It's not fair to obsess over runtime performance in a
> Lisp forum, because Lisp trades runtime optimization for many other
> things.

Fully agreed that there are trade-offs involved, and that picking on 
just performance isn't exactly fair.

I also agree that Lisp was unsurpassed for RAD, hotloading, and a few 
other things, and for quite a long while.
Today, however, I'd say that Lisp isn't the only language it its various 
niches anymore.

>  > My ability to assess the usefulness of macros is slightly limited.
>  > However, I'm having trouble with limiting what a macro can do.
>  > In principle, a macro can cause its parameters to be evaluated once,
>  > not at all, or an arbitrary number of times; it could do the
>  > evaluation at expansion time or at evaluation time.
> 
> No, macros are always called at expansion time, and they never evaluate
> their arguments.  The only thing that evaluates expressions at eval time
> is the code returned by the macro.

Hmm... that sounds definitely un-Lispish to me. Surely you can combine 
macros, or pass parameters that are evaluated by the macro (or when 
calling the macro) to control what the macro does?

Regards,
Jo
0
Reply jo427 (1164) 7/27/2007 3:31:15 PM

Sacha wrote:
> Lazyness is also useful for separation of concerns.
> read a file as if it was slurped entirely, process it as if it was fully
> available in memory, write the result as if they were all processed...
> But do it in constant space. And no need for complex interleaving code.
> 
> I think that's pretty nice !

Absolutely, but you don't want laziness everywhere all the time because it
means you can't write fast code.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 4:15:46 PM

Joachim Durchholz wrote:
> Hmm... that sounds definitely un-Lispish to me. Surely you can combine
> macros, or pass parameters that are evaluated by the macro (or when
> calling the macro) to control what the macro does?

A macro is just a term rewriter, like Mathematica, they accept trees and
spit out trees.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 4:17:29 PM

Sacha wrote:
>> As Haskell has shown, laziness cannot be implemented efficient at all.
> 
> As ruby and python have shown, programmers are only motivated by
> efficiency.

Theoretically good but practically bad performance is only suitable for
academics.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 4:18:22 PM

In article <46aa1cba$0$1600$ed2619ec@ptn-nntp-reader02.plus.net>,
 Jon Harrop <jon@ffconsultancy.com> wrote:

> Joachim Durchholz wrote:
> > Hmm... that sounds definitely un-Lispish to me. Surely you can combine
> > macros, or pass parameters that are evaluated by the macro (or when
> > calling the macro) to control what the macro does?
> 
> A macro is just a term rewriter, like Mathematica, they accept trees and
> spit out trees.

Paul Graham describes in his book 'On Lisp' the usage
of Common Lisp macros in detail. The book is now quite
expensive, but there is a free PDF you can download:

http://www.paulgraham.com/onlisp.html
http://www.paulgraham.com/onlisptext.html

-- 
http://lispm.dyndns.org
0
Reply joswig8642 (2198) 7/27/2007 4:37:26 PM

Joachim Durchholz wrote:

> In fact this is a long-standing gripe that I have been having about the 
> Lisp community. Disadvantages are discussed far more openly in other 
> communities (e.g. the Haskell community is quite open about the 
> advantages and disadvantages of laziness).

This is incorrect. Off the top of my head, I can think of the following 
issues that have been criticized openly in the Lisp community:

- Advantages and disadvantages (!) of macros
- Lisp-1 vs. Lisp-2
- presence and absence of full or partial continuations
- the multiple meanings of NIL
- iteration vs. recursion
- the CLOS Metaobject Protocol
- absence and presence of more reflective features, especially 
first-class environments
- the role of symbols
- package vs. module systems
- the size of the language: Common Lisp is often considered either too 
large or too small, depending on the discussant
- the fragmentation of the community (both Lisp in general and Common 
Lisp and Scheme specifically)
- the lack of a formal institutionalized process for further 
standardization for Common Lisp

This only captures a subset of typical discussions. For a current 
example of open criticism, you could also look at the discussion 
archives for the R6RS Scheme report.

Some of these issues are actually important.

Purported lack of efficiency and purportedly missing pattern matchers 
are usually not among the discussed issues.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/27/2007 4:43:00 PM

Jon Harrop wrote:
> Sacha wrote:
>>> As Haskell has shown, laziness cannot be implemented efficient at all.
>> As ruby and python have shown, programmers are only motivated by
>> efficiency.
> 
> Theoretically good but practically bad performance is only suitable for
> academics.
> 

I guess those guys at google are desperately theoretical.

Sacha
0
Reply none6154 (92) 7/27/2007 4:55:30 PM

On 2007-07-27, Joachim Durchholz <jo@durchholz.org> wrote:
> Dan Bensen schrieb:
>>  > My ability to assess the usefulness of macros is slightly
>>  > limited.  However, I'm having trouble with limiting what a macro
>>  > can do.  In principle, a macro can cause its parameters to be
>>  > evaluated once, not at all, or an arbitrary number of times; it
>>  > could do the evaluation at expansion time or at evaluation time.
>> 
>> No, macros are always called at expansion time, and they never
>> evaluate their arguments.  The only thing that evaluates
>> expressions at eval time is the code returned by the macro.
>
> Hmm... that sounds definitely un-Lispish to me. Surely you can
> combine macros, or pass parameters that are evaluated by the macro
> (or when calling the macro) to control what the macro does?

You guys are talking past each other.  Dan's talking about macros from
a strict technical sense and Joachim is talking not only about that,
but also about the code a macro generates.

  (defmacro example (a b c d)
    `(progn
	,b
	,c
	,c
	(eval (progn ,@d))))

This (generates code that) ignores A, evaluates B once, C twice, and D
at runtime.

0
Reply larry2780 (193) 7/27/2007 5:36:20 PM

Joachim Durchholz wrote:
> Hmm... that sounds definitely un-Lispish to me. Surely you can combine
> macros, or pass parameters that are evaluated by the macro (or when
> calling the macro) to control what the macro does?
> 

Well, there's some confusion here.  Of course you can pass parameters
to a macro - it's indeed  up to the macro what the heck it does with the
arguments.  But things in argument position for macros are not
evaluated and then passed to the macro like things in argument position
for functions are before being passed to the function.

-i.e. in (+ (* 2 2) moocow), + the function is going to see 4 and the
value of moocow passed to it.

in (m (* 2 2) moocow), macro m is called (at macroexpansion time) with
the list (* 2 2) and the symbol moocow.

Macros are considered to be "for" transforming code trees, and they
should output valid code trees when used in that capacity for obvious
reasons, but interpretation of their inputs and what the heck they
might actually do are not tightly constrained.
Fun link - Oleg Kiselyov enjoys doing particularly strange things:
http://okmij.org/ftp/Scheme/misc.html#lazy-stream 
"The second article demonstrates that Scheme/CL macro-expansion models
the non-strict computation of Haskell functions."






0
Reply david.golden (499) 7/27/2007 5:43:19 PM

Jon Harrop <jon@ffconsultancy.com> wrote on Fri, 27 Jul 2007:
> I think it is a real shame that so many people new to functional
> programming end up wasting their time with Lisp when they could be so much
> more productive using one of the modern FPLs.

But Common Lisp is not intended to be a "Functional Programming Language".
If that's the primary interest of a new programmer, and they settle on
Common Lisp, perhaps they've simply chosen the wrong community.

Common Lisp _is_ intended to be a tool for general programming, to write any
kind of algorithm.  If a new programmer has that goal, and instead narrowly
focuses only on "Functional Programming Languages", they have probably made
a similar mistake.

> A macro is simply a very rudimentary form of term rewriter and they are of
> limited utility in any language.

This is the kind of rude and unsupported statement that you continue to make,
despite the numerous attempts of Lisp folks to educate you on how macros are
actually used (and greatly valued) in Lisp.  Yet you persist, refusing (and
not even interested in) being educated.

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               don@geddis.org
--------- if you cut here, you'll probably destroy your monitor ----------
0
Reply don8867 (556) 7/27/2007 6:06:33 PM

Don Geddis wrote:
>> A macro is simply a very rudimentary form of term rewriter and they are
>> of limited utility in any language.
> 
> This is the kind of rude and unsupported statement...

Macros are a long way from a dedicated rewriter like a theorem prover or
computer algebra package.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 6:40:08 PM

Sacha wrote:
> I guess those guys at google are desperately theoretical.

Is someone at Google using a lazy language?

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 6:42:34 PM

Jon Harrop wrote:
> Sacha wrote:
>> I guess those guys at google are desperately theoretical.
> 
> Is someone at Google using a lazy language?
> 

I never said that.

 >>> As Haskell has shown, laziness cannot be implemented efficient at 
 >>> all.
 >>
 >> As ruby and python have shown, programmers are only motivated by
 >> efficiency.
 >
 >Theoretically good but practically bad performance is only suitable for
 >academics

I hear these guys at google use a fair bit of python. I might be 
mistaken, but my understanding was that this language is not very fast 
and would perform poorly in your ray-tracer benchmark. And yet, this 
rather successful company uses it. The services they provide are 
responsive enough in my opinion.

So it would seem raw language efficiency doesn't matter as much as you 
think when its about real life programming.

Abstraction is key, lazyness helps in this regard and comes at a price.

Of course it does.

The whole functional programming style is about abstraction over 
efficiency.

Sacha
0
Reply none6154 (92) 7/27/2007 7:47:12 PM

On Fri, 27 Jul 2007 16:57:03 +0200, Joachim Durchholz
<jo@durchholz.org> wrote:

>Tamas Papp schrieb:
>> Joachim Durchholz <jo@durchholz.org> writes:
>> 
>>> Lisp could thrive with predefined operator precedence plus
>>> indentation-is-parentheses (plus parentheses for those cases where you
>>> still need them), have 90% less parentheses, 30% more code per page,
>>> and *still* be simple to process macrologically.
>> 
>> It has been done -- would you claim that Dylan is thriving?
>
>If Dylan doesn't thrive, that might have any number of reasons.
>(Including unavailability of editors that can't properly block-indent, 
>NIY syndrome, and a couple of others.)

Actually Dylan had many supporters back when it used s-exprs.  Support
began to fall away when the operator precedence syntax was introduced.
At first programmers could use either syntax, but most users preferred
s-exprs and nearly everyone stopped using it when the s-expr syntax
was dropped (a move pushed by salespeople who didn't understand their
importance to Dylan's acceptance).

George
--
for email reply remove "/" from address
0
Reply George 7/27/2007 8:13:32 PM

On Jul 27, 11:40 am, Jon Harrop <j...@ffconsultancy.com> wrote:
> Don Geddis wrote:
> >> A macro is simply a very rudimentary form of term rewriter and they are
> >> of limited utility in any language.
>
> > This is the kind of rude and unsupported statement...
>
> Macros are a long way from a dedicated rewriter like a theorem prover or
> computer algebra package.

Macros are also a long way from a banana.

Harrop may believe that macros "a very rudimentary form of term
rewriter", but he's wrong.  Macros are a very powerful form of CODE
rewriter.  They can easily do things that would be difficult with a
theorem prover, algebra package, or banana.

Similarly, one can do things with a banana that would be difficult to
do with a macro.

Harrop has a bad case of "when all you have is a hammer, everything
looks like a nail".

Harrop is a blub.

0
Reply anamax (170) 7/27/2007 8:52:11 PM

Sacha wrote:
> I hear these guys at google use a fair bit of python. I might be
> mistaken, but my understanding was that this language is not very fast
> and would perform poorly in your ray-tracer benchmark. And yet, this
> rather successful company uses it. The services they provide are
> responsive enough in my opinion.

Absolutely.

> So it would seem raw language efficiency doesn't matter as much as you
> think when its about real life programming.

Depends what you're doing.

> Abstraction is key, lazyness helps in this regard and comes at a price.
> 
> Of course it does.
> 
> The whole functional programming style is about abstraction over
> efficiency.

Not in OCaml. :-)

My comment was trying to say that lazy languages still appear to be
considerably slower than eager languages in the context of a hypothetical
lazy Lisp being slow. I wasn't saying that performance is always important
which, as you say, it isn't.

However, functional programming doesn't require you to sacrifice run-time
performance (much) as, I think, OCaml and Stalin-compiled Scheme have
shown.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 10:23:39 PM

George Neuner schrieb:
> 
> Actually Dylan had many supporters back when it used s-exprs.  Support
> began to fall away when the operator precedence syntax was introduced.
> At first programmers could use either syntax, but most users preferred
> s-exprs and nearly everyone stopped using it when the s-expr syntax
> was dropped (a move pushed by salespeople who didn't understand their
> importance to Dylan's acceptance).

Strange, strange, strange.
Not that salespeople did dumb things (that's normal).
I'm a bit surprised that people have preferred the S-expressions. Did 
anybody give reasons? Was the drop in support due to changes to the 
syntax, or was it just a correlation?

Regards,
Jo
0
Reply jo427 (1164) 7/27/2007 10:46:02 PM

Larry Clapp schrieb:
> On 2007-07-27, Joachim Durchholz <jo@durchholz.org> wrote:
>> Dan Bensen schrieb:
>>>  > My ability to assess the usefulness of macros is slightly
>>>  > limited.  However, I'm having trouble with limiting what a macro
>>>  > can do.  In principle, a macro can cause its parameters to be
>>>  > evaluated once, not at all, or an arbitrary number of times; it
>>>  > could do the evaluation at expansion time or at evaluation time.
> 
> You guys are talking past each other.  Dan's talking about macros from
> a strict technical sense and Joachim is talking not only about that,
> but also about the code a macro generates.
> 
>   (defmacro example (a b c d)
>     `(progn
> 	,b
> 	,c
> 	,c
> 	(eval (progn ,@d))))
> 
> This (generates code that) ignores A, evaluates B once, C twice, and D
> at runtime.

Ah, thanks.
Then my original assumptions do indeed hold.

Regards,
Jo
0
Reply jo427 (1164) 7/27/2007 10:48:49 PM

Andy Freeman wrote:
> Harrop may believe that macros "a very rudimentary form of term
> rewriter", but he's wrong.

Then you'll be able to translate this Mathematica term rewriter into a
similarly-elegant Lisp macro. This finds all sublists that are flanked by
the same element:

  ReplaceList[{a, b, c, a, d, b, d}, {___, x_, y__, x_, ___} -> g[x, {y}]]
  {g[a, {b, c}], g[b, {c, a, d}], g[d, {b}]}

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/27/2007 11:06:48 PM

Joachim Durchholz wrote:
> George Neuner schrieb:
>>
>> Actually Dylan had many supporters back when it used s-exprs.  Support
>> began to fall away when the operator precedence syntax was introduced.
>> At first programmers could use either syntax, but most users preferred
>> s-exprs and nearly everyone stopped using it when the s-expr syntax
>> was dropped (a move pushed by salespeople who didn't understand their
>> importance to Dylan's acceptance).
> 
> Strange, strange, strange.
> Not that salespeople did dumb things (that's normal).
> I'm a bit surprised that people have preferred the S-expressions. Did 
> anybody give reasons? Was the drop in support due to changes to the 
> syntax, or was it just a correlation?

I am not surprised at all. Apparently, the main target audience 
effectively were Lispers, and Lispers who have considerably experience 
with s-expressions typically prefer them over more mainstream syntaxes.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
0
Reply pc56 (3896) 7/27/2007 11:53:29 PM

On Jul 27, 4:06 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Andy Freeman wrote:
> > Harrop may believe that macros "a very rudimentary form of term
> > rewriter", but he's wrong.
>
> Then you'll be able to translate this Mathematica term rewriter into a
> similarly-elegant Lisp macro.

Harrop "forgot" to quote the very next sentence, where I explained
what lisp macros are.  I'll do so.

>>Harrop may believe that macros "a very rudimentary form of term
>>rewriter", but he's wrong.  Macros are a very powerful form of CODE
>>rewriter.

If Harrop believes that code and terms are the same thing, that's just
one more thing that he's wrong about.

Interestingly enough, the next two sentence answer the argument Harrop
is trying to make.

>> ...      They can easily do things that would be difficult with a
>>theorem prover, algebra package, or banana.
>>
>>Similarly, one can do things with a banana that would be difficult to
>>do with a macro.

In other words, theorem provers are good at different things than code
rewriters.  Too bad Harrop's tool is only good at one thing.

> This finds all sublists that are flanked by the same element:

Why would one need, or even use, a code rewriter for that
functionality?  Heck, why does one even need a term rewriter?  The
following simple python suffices.  (Note that it can be used in more
circumstances than Harrop's obscurity and can be turned into a
generator.)

class Matched:
    def __init__(self):
        self._accumulators = {}
        self.completed = {}

    def addSeq(self, seq):
        for e in seq:
            for k in self._accumulators:
                self._accumulators[k].append(e)
            if e in self._accumulators:
                # p is useful for an generator version
                p = self._accumulators[e][:-1]
                self.completed.setdefault(e, []).append(p)
                # yield p
            self._accumulators[e] = []



0
Reply anamax (170) 7/28/2007 12:54:28 AM

On 2007-07-27 06:48:51 -0400, 
development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus 
E.L.) said:

> And thanks for bringing all that to c.l.f. BTW: Does that qualify as
> spam by your questionnaire? I can't decide from the top off my head.

Do you see any commercial advertisting in my post? Don't know about the 
top of your head, but the inside seems farily vacant.

0
Reply Raffael 7/28/2007 4:32:48 AM

Andy Freeman <anamax@earthlink.net> writes:

> On Jul 27, 4:06 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> > Andy Freeman wrote:
> > > Harrop may believe that macros "a very rudimentary form of term
> > > rewriter", but he's wrong.
> >
> > Then you'll be able to translate this Mathematica term rewriter into a
> > similarly-elegant Lisp macro.
> 
> Harrop "forgot" to quote the very next sentence, where I explained
> what lisp macros are.

Indeed.  In Lisp, the notion of a "macro" is just "any program that
takes forms as input and yields forms as output" ... BUT applied at
compile time to forms that are presented for semantic processing
(evaluation or compilation).  That is, a function such as:

(defun shrug (list)
  (loop for (x . sublist-and-more) on list
        for more = (member x sublist-and-more)
        when more
         collect `(g ,x ,(ldiff sublist-and-more more))))
=> SHRUG

(shrug '(a b c a d b d))
=> ((G A (B C)) (G B (C A D)) (G D (B)))

For this to be a macro, you'd want to have done something to get it called
at semantic processing time, as in:

(defmacro shrug-too (&rest list)
  `',(shrug list))
=> SHRUG-TOO

(shrug-too a b c a d b d)
=> ((G A (B C)) (G B (C A D)) (G D (B)))

Of course, I didn't decide the boring nature of this "macro".
Spicing it up slightly...

(defun hohum (list &key (op 'op) (transform #'identity))
  (loop for (x . sublist-and-more) on list
        for more = (member x sublist-and-more)
        when more
          collect `(,op ,(funcall transform x)
                        ,(funcall transform (ldiff sublist-and-more more)))))
=> HOHUM

(hohum '(a b c a d b d) :op 'g)
=> ((G A (B C)) (G B (C A D)) (G D (B)))

(defmacro hohum-too (&rest forms)
  (flet ((quotify (x) `',x))
   `(flet ((show (x y) (print (list y 'between x))))
      ,@(hohum forms :op 'show :transform #'quotify)
      ',forms)))
=> HOHUM-TOO

(hohum-too a b c a d b d x e d)

((B C) BETWEEN A) 
((C A D) BETWEEN B) 
((B) BETWEEN D) 
((X E) BETWEEN D) 
=> (A B C A D B D X E D)

(pprint (macroexpand-1 '(hohum-too a b c a d b d x e d)))

(FLET ((SHOW (X Y) (PRINT (LIST Y 'BETWEEN X))))
  (SHOW 'A '(B C))
  (SHOW 'B '(C A D))
  (SHOW 'D '(B))
  (SHOW 'D '(X E))
  '(A B C A D B D X E D))

In general, Lisp programs would not tend to do this kind of thing at macro
expansion time, since that limits the utility of the operation to patterns
to be rewritten that are known at compile time (and hence are not application
data).  We call things that operate on data at runtime "functions", as Andy
correctly observes.
0
Reply pitman (1396) 7/28/2007 5:31:17 AM

Andy Freeman wrote:
> > ReplaceList[{a, b, c, a, d, b, d}, {___, x_, y__, x_, ___} -> g[x, {y}]]
>
> class Matched:
>     def __init__(self):
>         self._accumulators = {}
>         self.completed = {}
> 
>     def addSeq(self, seq):
>         for e in seq:
>             for k in self._accumulators:
>                 self._accumulators[k].append(e)
>             if e in self._accumulators:
>                 # p is useful for an generator version
>                 p = self._accumulators[e][:-1]
>                 self.completed.setdefault(e, []).append(p)
>                 # yield p
>             self._accumulators[e] = []

As you can see, the dedicated term rewriter is better at rewriting terms.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/28/2007 9:51:37 AM

development-2006-8ecbb5cc8aREMOVETHIS@ANDTHATm-e-leypold.de (Markus E.L.) writes:

> Call me a troll. :-) You wouldn't be the first one.

OK, thanks for making this clear.

Nicolas
0
Reply lastname1 (71) 7/28/2007 10:06:39 AM

Joachim Durchholz <jo@durchholz.org> writes:

> I'm a bit surprised that people have preferred the S-expressions. Did 
> anybody give reasons?

I think we confuse ourselves when we frame the issue using
the phrase "preferred the S-expressions." I've seen old LISP
documents that wrote LISP code in filled paragraphs. It was
horrible.

Programmers evolved layout conventions that work well with
S-expressions.

For example

        2xyz
 ----------------
        2    2
   3 ( x  + y )

becomes

(/ (* 2 x y z)
   3 (+ (expt x 2) (expt y 2)))

COND clauses could be written as run-on sentences (cond
((test for this)(do this))((test for that)(do something
else))((test number three)(third action))((final test)(catch
all case)).

We don't do that. We lay it out in a two dimensional
rule-action table.

(cond
  ((test for this) (do this))
  ((test for that) (do something else))
  ((test number three) (third action))
  ((final test) (catch all case)))

My point is that both ways are S-expressions, but the Lisp
community makes a sharp distinction. Newbies are always
being told to indent their code properly, using the tools
built in to their editor. We see the first way as bad and
the second way as good. "S-expressions" straddles the
good/bad boundary. Asking people about their preferences,
using a boundary straddling term that includes what they
energetically reject gets the discussion off to an
irretrievably bad start.

Alan Crowe
Edinburgh
Scotland
0
Reply alan8762 (478) 7/28/2007 10:48:53 AM

Jon Harrop <jon@ffconsultancy.com> wrote on Sat, 28 Jul 2007:
> As you can see, the dedicated term rewriter is better at rewriting terms.

Which surprises no one.  Similarly, a dedicated graphics library will be
better for implementing graphics programs.

Some of us (but not you, apparently) are aware that there is more to
computation than just term rewriting.

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               don@geddis.org
If a kid asks where rain comes from, I think a cute thing to tell him is "God
is crying."  And if he asks why God is crying, another cute thing to tell him
is "Probably because of something you did."  -- Deep Thoughts, by Jack Handey
0
Reply don8867 (556) 7/28/2007 4:04:17 PM

Don Geddis <don@geddis.org> writes:

> Some of us ... are aware that there is more to computation than just
> term rewriting.

Which is why CL focuses on providing tools that allow people to modify
what they get out-of-the-box in order to bootstrap an environment they
like to program in.

If the poster in question had spent half as much time learning the
language and implementing tools, instead of simply criticizing the
language groundlessly, he'd by now have had plenty of time to
implement a very nice term rewriting library of his own ... and could
be offering it for sale to the vast numbers of people who have been
holding off in their use of Lisp until that important linguistic gap
was filled.  (I'd rush to do it myself, but I'd hate to rob someone of
such a hard-earned ticket to fame and fortune.)
0
Reply pitman (1396) 7/28/2007 4:44:16 PM

Markus E.L. wrote:
> May I contradict here? I thought, most of the Schemes have a decent
> performance, even with callcc?

SML/NJ is another one to look at: it transforms into CPS before compilation
so (AFAIK) there is no non-persistent stack. I believe all such languages
are significantly slower than those with conventional stacks.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/28/2007 4:44:17 PM

Markus E.L. wrote:
> If I see it right, data flow analysis is tightly related to automatic
> type derivation. Indeed I like the idea that one can get an untyped
> language and the type systems as external tools to be applied at will
> and where needed. I understood Qi to be exactly such a system. The
> only problem I see, is, that typing also directs the compiler in
> optimization and choosing data representations (or should/does in a
> language like ML).

Surely it is much easier to remove a static type system than to add one. I
would advocate an approach like .NET, where the run-time has a simple
static type system, giving good performance and conveying some static type
information between languages.

So real users can exploit sophisticated statically-typed languages that ride
on .NET to design spacecraft or cure cancer and the users who struggle with
maths can lash together their shopping trolleys for porn sites using
dynamically typed languages like IronPython.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/28/2007 4:55:58 PM

Markus E.L. wrote:
> But never mind: You are welcome to your community. Jon, in my opinion
> is not a spammer (is not outside c.l.l.) but certainly a fool trying
> to talk to such a self contained community as c.l.l. seems to be: The
> effort is ill spent, and it's hardly thinkable that the resulting
> flame wars will get him any customers there (if that should be the
> purpose), quite the opposite.

When I post clarifications I'm not addressing the vocal die-hard Lispers who
struggle with arithmetic, I'm trying to help the newbies who are being
misled.

I'd do the same thing if I saw a child being taught scientific creationism,
for example.

-- 
Dr Jon D Harrop, Flying Frog Consultancy
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?usenet
0
Reply jon (3267) 7/28/2007 5:00:31 PM

Jon Harrop schrieb:

> However, functional programming doesn't require you to sacrifice run-time
> performance (much) as, I think, OCaml and Stalin-compiled Scheme have
> shown.

In the long run it is only about productivity.
With compilers that nearly match human intelligence all programs would
result in the end in the same, highly optimized machine language output.
Those compilers are not available now, but I think many of us will see
them within their livetime.
Until then Lisp is for most things the best bet. It performs fast enough,
for most tasks close to C or faster (simply because it would be too
complicated to write a complex program in C).
It is not fixed into a specific paradigm, like functional programming
or logic programming. It is the only truly multiparadigm programming
language and one can create domain specific languages easier than any
other language. This means of course unbeatable productivity, as no
general purpose language could compete with a domain specific one.


Andr�
-- 
0
Reply address.good.until.2