Matt's Blog

Looping without loops

Sun Sep 17 18:09:04 EST 2006

A standard exercise when first learning to program is to draw a triangle of stars using for loops, i.e.


How do you do this in a language that doesn't allow variable assignment? By (tail) recursion with an extra accumulator argument and loop index. Below is the Ocaml code for drawing a number of different triangles. Note the use of the higher order function string_gen.

let make_line c n = String.make n c

let make_tri c n =
  let rec aux k acc =
    if k=0 then acc else aux (k-1) ((make_line c k) :: acc)
  in aux n []

let string_gen shift_fun ind_update lst =
  snd (List.fold_left
    (fun (ind,acc) x -> (ind_update ind,
                         acc ^ (shift_fun ind) ^ x ^ "\n"))
    (0,"") lst)

let odd_els lst =
  List.rev (snd (List.fold_left
        (fun (ind, acc) x -> if ind=0 then (1,x::acc) else (0,acc))
        (0,[]) lst))

(* Offset all strings in list by n spaces *)
let offset n lst = (fun x-> (String.make n ' ') ^ x) lst

let up_left_tri n =
  string_gen (fun x->"") (fun x->x) (make_tri '*' n)
let up_right_tri n =
  string_gen (fun x-> String.make (n-1-x) ' ')
             (fun x->x+1) (make_tri '*' n)
let dn_left_tri n =
  string_gen (fun x->"") (fun x->x) (List.rev (make_tri '*' n))
let dn_right_tri n =
  string_gen (fun x-> String.make x ' ') (fun x->x+1)
  (List.rev (make_tri '*' n))
let up_sym_tri n =
  string_gen (fun x-> String.make (n-1-x) ' ') (fun x->x+1)
  (odd_els (make_tri '*' (2*n)))
let dn_sym_tri n =
  string_gen (fun x-> String.make x ' ') (fun x->x+1)
  (List.rev (odd_els (make_tri '*' (2*n))))
let dn_sym_tri_offset d n =
  string_gen (fun x-> String.make x ' ') (fun x->x+1)
  (offset d (List.rev (odd_els (make_tri '*' (2*n)))))

let draw_ul n = Printf.printf "%s" (up_left_tri n)
let draw_ur n = Printf.printf "%s" (up_right_tri n)
let draw_dl n = Printf.printf "%s" (dn_left_tri n)
let draw_dr n = Printf.printf "%s" (dn_right_tri n)
let draw_us n = Printf.printf "%s" (up_sym_tri n)
let draw_ds n = Printf.printf "%s" (dn_sym_tri n)
let draw_dia n = Printf.printf "%s%s"
  (up_sym_tri n) (dn_sym_tri_offset 1 (n-1))



code (24)

erlang (5)
ideas (19)
lisp (1)
me (11)
notes (4)
ocaml (1)
physics (45)
qo (7)
unix (6)
vim (3)