Computer Chess Club Archives


Search

Terms

Messages

Subject: The Glory that is ML (long and not for the faint of heart)

Author: Anthony Cozzie

Date: 05:43:21 08/01/03

Go up one level in this thread


(some stuff snipped)

>And don't derive cat and dog from animal ;-)
>It depends, you can teach procedural things first, algorithms and data
>structures. Control flow etc. Why not Pascal or Delphi?

But most intro courses, sadly, focus on the Language first.  At CMU, students
don't do any algorithms until 2nd semester (15-211).

>>P.S. my favorite language is ML, but Zappa is in a mixture of C, C++, and
>>assembly.
>
>never heard about ML, can you give me a glue?

ML was developed to write compliers in.  Ocaml is the french version; Ocaml is
generally considered to be about 1.5x as slow as 'C' code (do a search on
"programming languages shootout").  My examples are written in SML (standard
ML).

There are two really neat features of ML.  First, the typesafing, and secondly
the fact that you can think onto the page.

In 'C', you declare your functions with types:
int foot(int r, char *s, ...);

In ML, you just write the function:
fun exp(a, b, c) = BLAH
   |exp(0, b, c) = FOO

etc.

Now, the marvel of all this, is that the ML compiler is given this huge mess of
stuff, and it has to figure out what type everything is (because ML is a
strongly typed language).  Now, if BLAH evaluates to an int, and FOO evaluates
to a char, you have some sort of a problem.  This doesn't sound that helpful,
but ML allows you to build up crazy types.  Here are two sample ML programs from
my stay in 15212.

Problem 3: Regular Expressions

This problem does regular expression matching: does string aaabba match a*b*a
etc.  In 'C', this would be several hundred lines.  This program is very
complicated because it uses continuations.  The basic idea is that K (the
continuation) is a function that matches "the rest".

P.S. I didn't get full points for this problem.  Find the error if you can.
(sadly, my TA could)

structure Regex :> REGEX =
struct
  datatype regExp =
    Char of char
  | Concat of regExp * regExp
  | Epsilon
  | Union of regExp * regExp
  | Empty
  | Star of regExp
  | Underscore (matches anything)
  | And of regExp * regExp
  | Top
  | Not of regExp

  fun acc (Char(a)) (nil) k = false
     |acc (Char(a)) (b::s) k = if a = b then k s else false
     |acc (Epsilon) s k = k s
     |acc (Empty) s k = false
     |acc (Union(r1,r2)) s k = acc r1 s k orelse acc r2 s k
     |acc (Concat(r1,r2)) s k = acc r1 s (fn s' => acc r2 s' k)
     |acc (r as Star(r1)) s k = k s orelse acc r1 s (fn s' => if s = s' then fal
se else acc r s' k)
     |acc (Underscore) (nil) k = false
     |acc (Underscore) (b::s) k = k s
     |acc (And(r1,r2)) s k = acc r1 s k andalso acc r2 s k
     |acc (Top) s k = acc (Star(Underscore)) s k
     |acc (Not(r)) s k = if (acc r s (fn s' => if (k s) then false else true) th
en false else true

  fun accept r s = acc r (String.explode s) (fn nil => true | x => false)
end

/* test code*/
val a = Char(#"a")
val b = Char(#"b")
val accept_aa = accept (Concat(a,a));
val accept_aorbstar = accept (Star(Union(a,b)));
val accept_aborastar = accept (Star(Union(Concat(a,b),a)));
val accept_xaay = accept
(Concat(Concat(Concat(Star(Union(a,b)),a),a),Star(Union(a,b))));
val test1 = accept_aorbstar "abababbbcaabaaba"
val accept_naa = accept (Concat(b,Not(Star(a))));
val test2 = accept (And(Concat(a,Top),Concat(Top,b))) "ajdsfsla"
val test3 = accept (Not(Top)) "b" (*match if a - not a*)

Problem 2: Trominoes

A Tromino is a block made of 3 blocks.  Think of it as a square divided into
corners with one missing. The problem is to fill an arbitrarily large square
with trominoes.  The amazing thing about this is how the translate function
matches the proof exactly.

Notes: ~1 is minus one.  @ means concatenate the items into a list.  :: means
split/join a list. nil is the empty
list.

Proof:

Base Case: A 2x2 square with one tromino will have one empty
 square at an arbitrary corner.

Induction Case: Assume that a 2^n * 2^n square can be covered
  with trominoes with one empty square remaining, and that
  square can be placed at an arbitrary corner.

Suppose we have a 2^(n+1) * 2(n+1) square. This can be divided up
  into 4 2^n * 2^n squares.  Place them such that 3 of the squares
  align their empty corners in the center, and one such that the
  empty corner is at a corner of the larger square.  Fill the three
  corners in the center with another tromino.  This new square is
  now completely filled trominoes except for one corner, and can
  be rotated/flipped to move that empty square to an arbitrary corner.
  Done. *)

datatype orientation = NW | NE | SW | SE
type tromino = int * int * orientation -> this means a tromino is struct { int,
int, orientation }

fun translate nil (dx,dy) = nil
   |translate ((a,b,c)::h) (dx,dy) = (a+dx,b+dy,c)::(translate h (dx,dy))

fun flip nil r  = nil
   |flip ((a,b,NE)::x) r = (a,~1*b+1+r,SE)::(flip x r)
   |flip ((a,b,NW)::x) r = (a,~1*b+1+r,SW)::(flip x r)
   |flip ((a,b,SE)::x) r = (a,~1*b+1+r,NE)::(flip x r)
   |flip ((a,b,SW)::x) r = (a,~1*b+1+r,NW)::(flip x r)

fun invert nil r = nil
   |invert ((a,b,NE)::x) r = (~1*a+1+r, b, NW)::(invert x r )
   |invert ((a,b,NW)::x) r = (~1*a+1+r, b, NE)::(invert x r )
   |invert ((a,b,SE)::x) r = (~1*a+1+r, b, SW)::(invert x r )
   |invert ((a,b,SW)::x) r = (~1*a+1+r, b, SE)::(invert x r )

fun exp( a, 0 ) = 1
   |exp( a, b ) = a * (exp ( a, b - 1 ))

fun tile( 1 ) = [(1,1,NE)]
   |tile( n ) = let val r = exp( 2, n - 1) in
                  (translate (invert (tile (n-1)) r) (0,r))
                 @(translate (flip (tile (n-1)) r) (r,0))
                 @(translate (tile (n-1)) (r,r))
                 @(tile (n-1))
                 @[(r,r,NE)] end



This page took 0.01 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.