Voting

Category

real language

Bookmarking

Del.icio.us Digg Diigo DZone Earthlink Google Kick.ie
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

Language OCaml

(version with recursive variant type)

Date:11/18/05
Author:Pierre Etchemaïté
URL:n/a
Comments:1
Info:http://www.ocaml.org/
Score: (2.93 in 14 votes)
(* We first build the datastructure of the whole song, then convert it
   to its text form.

   This demonstrates recursive variants, tuple and record types.
 *)

type lyrics =
    | Strophe of strophe
    | Verse of lyrics * lyrics (* hemistichs *)
    | Bottle of int
    | Wall of lyrics
    | TakeOneDown
    | GoToTheStore
    | TheEnd
and strophe =
    { verse1 : lyrics; verse2 : lyrics; remaining : lyrics }

let build_lyrics n0 =
  let rec build_strophe n =
    if n > 0 then
      Strophe { verse1 = Verse (Wall (Bottle n), Bottle n);
                verse2 = Verse (TakeOneDown, Wall (Bottle (n-1)));
                remaining = build_strophe (n-1) }
    else
      Strophe { verse1 = Verse (Wall (Bottle n), Bottle n);
                verse2 = Verse (GoToTheStore, Wall (Bottle n0));
                remaining = TheEnd }
  in build_strophe n0

let rec lyrics_to_string l =
  let strophe_to_string s =
    (lyrics_to_string s.verse1) ^ "\n" ^ (lyrics_to_string s.verse2) ^ "\n" in
  match l with
  | TheEnd -> ""
  | Strophe ({ remaining = TheEnd } as s) ->
      strophe_to_string s
  | Strophe ({ remaining = next } as s) ->
      (strophe_to_string s) ^ "\n" ^ (lyrics_to_string next)
  | Verse (hemistich1, hemistich2) ->
      String.capitalize ( (lyrics_to_string hemistich1) ^ ", " ^
                          (lyrics_to_string hemistich2) ^ "." )
  | Bottle n ->
      (match n with
         | 0 -> "no more bottles"
         | 1 -> "1 bottle"
         | n -> (string_of_int n) ^ " bottles") ^ " of beer"
  | Wall l ->
      (lyrics_to_string  l) ^ " on the wall"
  | TakeOneDown ->
      "take one down and pass it around"
  | GoToTheStore ->
      "go to the store and buy some more"

let _ =
  print_string (lyrics_to_string (build_lyrics 99))

Download Source | Write Comment

Alternative Versions

VersionAuthorDateCommentsRate
working with new versions, using printfDavid Baelde11/08/050
functional versionAnonymous04/20/050
A little modification to the current onePhilippe Wang01/28/061
historic versionPhilipp Winterberg04/20/050

Comments

>>  petchema said on 03/26/06 03:13:08

petchema To take the defense of my variant, such style is not purely artificial; It's even common in compilers, code generators, etc. (See Abstract Syntax Trees http://en.wikipedia.org/wiki/Abstract_syntax_tree).
In this "99 bottles" case, while this variant is larger than others, it has its own merits: it allows to separate problems.
Want to implement variants of the song ? Modify the generator.
Want to output XML, HTML, Postscript ? Or output the song in german ? Modify the printer.
The AST type probably needs changes however ;)

If you worry about performance... Well first, that version is still plenty fast.
However, lazy values could be used so that the AST is only computed as needed (and even probably partially garbage collected during output...). And printer could either do direct I/O to avoid keeping whole text in memory, or at least use Buffer to generate it efficiently. Exercice left to the reader, I wanted to keep the code easy to grasp...

Download Source | Write Comment

Add Comment

Please provide a value for the fields Name, Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.

Please don't post large portions of code here! Use the form to submit new examples or updates instead!

Name:

eMail:

URL:

Security Code:
  
Comment: